aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorFrankie <frankie.diamond@gmail.com>2017-01-29 14:59:28 +0800
committerFrankie <frankie.diamond@gmail.com>2017-01-29 14:59:28 +0800
commitfdee1e3701a84fe1321de348ec2d11bf5361a62d (patch)
tree1844d6c25cc824c9303ab79103525cab08d5e0b3 /app
parent8be68575bbef1dcc89b51355abaee90dbf018387 (diff)
parent47b48c0e02b2b9508813abfda0d89a1bbe677694 (diff)
downloadtangerine-wallet-browser-fdee1e3701a84fe1321de348ec2d11bf5361a62d.tar
tangerine-wallet-browser-fdee1e3701a84fe1321de348ec2d11bf5361a62d.tar.gz
tangerine-wallet-browser-fdee1e3701a84fe1321de348ec2d11bf5361a62d.tar.bz2
tangerine-wallet-browser-fdee1e3701a84fe1321de348ec2d11bf5361a62d.tar.lz
tangerine-wallet-browser-fdee1e3701a84fe1321de348ec2d11bf5361a62d.tar.xz
tangerine-wallet-browser-fdee1e3701a84fe1321de348ec2d11bf5361a62d.tar.zst
tangerine-wallet-browser-fdee1e3701a84fe1321de348ec2d11bf5361a62d.zip
Merge branch 'dev' into messageManagerCleanUp
Diffstat (limited to 'app')
-rw-r--r--app/scripts/keyring-controller.js101
-rw-r--r--app/scripts/lib/config-manager.js10
-rw-r--r--app/scripts/metamask-controller.js257
-rw-r--r--app/scripts/migrations/005.js41
-rw-r--r--app/scripts/migrations/index.js1
5 files changed, 236 insertions, 174 deletions
diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js
index b6c9aa3a7..b56b5520f 100644
--- a/app/scripts/keyring-controller.js
+++ b/app/scripts/keyring-controller.js
@@ -1,12 +1,12 @@
const ethUtil = require('ethereumjs-util')
+const BN = ethUtil.BN
const bip39 = require('bip39')
const EventEmitter = require('events').EventEmitter
+const ObservableStore = require('obs-store')
const filter = require('promise-filter')
const encryptor = require('browser-passworder')
-
-const normalize = require('./lib/sig-util').normalize
-const BN = ethUtil.BN
-
+const normalizeAddress = require('./lib/sig-util').normalize
+function noop () {}
// Keyrings:
const SimpleKeyring = require('./keyrings/simple')
const HdKeyring = require('./keyrings/hd')
@@ -15,7 +15,7 @@ const keyringTypes = [
HdKeyring,
]
-module.exports = class KeyringController extends EventEmitter {
+class KeyringController extends EventEmitter {
// PUBLIC METHODS
//
@@ -26,6 +26,8 @@ module.exports = class KeyringController extends EventEmitter {
constructor (opts) {
super()
+ const initState = opts.initState || {}
+ this.store = new ObservableStore(initState)
this.configManager = opts.configManager
this.ethStore = opts.ethStore
this.encryptor = encryptor
@@ -65,27 +67,29 @@ module.exports = class KeyringController extends EventEmitter {
// in this class, but will need to be Promisified when we move our
// persistence to an async model.
getState () {
- const configManager = this.configManager
- const address = configManager.getSelectedAccount()
- const wallet = configManager.getWallet() // old style vault
- const vault = configManager.getVault() // new style vault
- const keyrings = this.keyrings
-
- return Promise.all(keyrings.map(this.displayForKeyring))
+ return Promise.all(this.keyrings.map(this.displayForKeyring))
.then((displayKeyrings) => {
+ const state = this.store.getState()
+ // old wallet
+ const wallet = this.configManager.getWallet()
return {
+ // computed
+ isInitialized: (!!wallet || !!state.vault),
+ isUnlocked: (!!this.password),
+ keyrings: displayKeyrings,
+ // hard coded
+ keyringTypes: this.keyringTypes.map(krt => krt.type),
+ // memStore
+ identities: this.identities,
+ // diskStore
+ selectedAccount: state.selectedAccount,
+ // configManager
seedWords: this.configManager.getSeedWords(),
- isInitialized: (!!wallet || !!vault),
- isUnlocked: Boolean(this.password),
isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(),
- selectedAccount: address,
- shapeShiftTxList: this.configManager.getShapeShiftTxList(),
currentFiat: this.configManager.getCurrentFiat(),
conversionRate: this.configManager.getConversionRate(),
conversionDate: this.configManager.getConversionDate(),
- keyringTypes: this.keyringTypes.map(krt => krt.type),
- identities: this.identities,
- keyrings: displayKeyrings,
+ // messageManager
}
})
}
@@ -138,8 +142,8 @@ module.exports = class KeyringController extends EventEmitter {
.then((accounts) => {
const firstAccount = accounts[0]
if (!firstAccount) throw new Error('KeyringController - First Account not found.')
- const hexAccount = normalize(firstAccount)
- this.configManager.setSelectedAccount(hexAccount)
+ const hexAccount = normalizeAddress(firstAccount)
+ this.setSelectedAccount(hexAccount)
return this.setupAccounts(accounts)
})
.then(this.persistAllKeyrings.bind(this, password))
@@ -236,9 +240,9 @@ module.exports = class KeyringController extends EventEmitter {
//
// Sets the state's `selectedAccount` value
// to the specified address.
- setSelectedAccount (address) {
- var addr = normalize(address)
- this.configManager.setSelectedAccount(addr)
+ setSelectedAccount (account) {
+ var address = normalizeAddress(account)
+ this.store.updateState({ selectedAccount: address })
return this.fullUpdate()
}
@@ -250,11 +254,19 @@ module.exports = class KeyringController extends EventEmitter {
//
// Persists a nickname equal to `label` for the specified account.
saveAccountLabel (account, label) {
- const address = normalize(account)
- const configManager = this.configManager
- configManager.setNicknameForWallet(address, label)
- this.identities[address].name = label
- return Promise.resolve(label)
+ try {
+ const hexAddress = normalizeAddress(account)
+ // update state on diskStore
+ const state = this.store.getState()
+ const walletNicknames = state.walletNicknames || {}
+ walletNicknames[hexAddress] = label
+ this.store.updateState({ walletNicknames })
+ // update state on memStore
+ this.identities[hexAddress].name = label
+ return Promise.resolve(label)
+ } catch (err) {
+ return Promise.reject(err)
+ }
}
// Export Account
@@ -270,7 +282,7 @@ module.exports = class KeyringController extends EventEmitter {
try {
return this.getKeyringForAccount(address)
.then((keyring) => {
- return keyring.exportAccount(normalize(address))
+ return keyring.exportAccount(normalizeAddress(address))
})
} catch (e) {
return Promise.reject(e)
@@ -284,7 +296,7 @@ module.exports = class KeyringController extends EventEmitter {
// TX Manager to update the state after signing
signTransaction (ethTx, _fromAddress) {
- const fromAddress = normalize(_fromAddress)
+ const fromAddress = normalizeAddress(_fromAddress)
return this.getKeyringForAccount(fromAddress)
.then((keyring) => {
return keyring.signTransaction(fromAddress, ethTx)
@@ -328,8 +340,8 @@ module.exports = class KeyringController extends EventEmitter {
.then((accounts) => {
const firstAccount = accounts[0]
if (!firstAccount) throw new Error('KeyringController - No account found on keychain.')
- const hexAccount = normalize(firstAccount)
- this.configManager.setSelectedAccount(hexAccount)
+ const hexAccount = normalizeAddress(firstAccount)
+ this.setSelectedAccount(hexAccount)
this.emit('newAccount', hexAccount)
return this.setupAccounts(accounts)
})
@@ -365,7 +377,7 @@ module.exports = class KeyringController extends EventEmitter {
if (!account) {
throw new Error('Problem loading account.')
}
- const address = normalize(account)
+ const address = normalizeAddress(account)
this.ethStore.addAccount(address)
return this.createNickname(address)
}
@@ -377,10 +389,11 @@ module.exports = class KeyringController extends EventEmitter {
//
// Takes an address, and assigns it an incremented nickname, persisting it.
createNickname (address) {
- const hexAddress = normalize(address)
- var i = Object.keys(this.identities).length
- const oldNickname = this.configManager.nicknameForWallet(address)
- const name = oldNickname || `Account ${++i}`
+ const hexAddress = normalizeAddress(address)
+ const currentIdentityCount = Object.keys(this.identities).length + 1
+ const nicknames = this.store.getState().walletNicknames || {}
+ const existingNickname = nicknames[hexAddress]
+ const name = existingNickname || `Account ${currentIdentityCount}`
this.identities[hexAddress] = {
address: hexAddress,
name,
@@ -415,7 +428,7 @@ module.exports = class KeyringController extends EventEmitter {
return this.encryptor.encrypt(this.password, serializedKeyrings)
})
.then((encryptedString) => {
- this.configManager.setVault(encryptedString)
+ this.store.updateState({ vault: encryptedString })
return true
})
}
@@ -428,7 +441,7 @@ module.exports = class KeyringController extends EventEmitter {
// Attempts to unlock the persisted encrypted storage,
// initializing the persisted keyrings to RAM.
unlockKeyrings (password) {
- const encryptedVault = this.configManager.getVault()
+ const encryptedVault = this.store.getState().vault
if (!encryptedVault) {
throw new Error('Cannot unlock without a previous vault.')
}
@@ -508,7 +521,7 @@ module.exports = class KeyringController extends EventEmitter {
// Returns the currently initialized keyring that manages
// the specified `address` if one exists.
getKeyringForAccount (address) {
- const hexed = normalize(address)
+ const hexed = normalizeAddress(address)
return Promise.all(this.keyrings.map((keyring) => {
return Promise.all([
@@ -517,7 +530,7 @@ module.exports = class KeyringController extends EventEmitter {
])
}))
.then(filter((candidate) => {
- const accounts = candidate[1].map(normalize)
+ const accounts = candidate[1].map(normalizeAddress)
return accounts.includes(hexed)
}))
.then((winners) => {
@@ -575,7 +588,9 @@ module.exports = class KeyringController extends EventEmitter {
this.keyrings = []
this.identities = {}
- this.configManager.setSelectedAccount()
+ this.setSelectedAccount()
}
}
+
+module.exports = KeyringController
diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js
index fd4ac511a..357e081b1 100644
--- a/app/scripts/lib/config-manager.js
+++ b/app/scripts/lib/config-manager.js
@@ -29,15 +29,7 @@ ConfigManager.prototype.setConfig = function (config) {
ConfigManager.prototype.getConfig = function () {
var data = this.getData()
- if ('config' in data) {
- return data.config
- } else {
- return {
- provider: {
- type: 'testnet',
- },
- }
- }
+ return data.config
}
ConfigManager.prototype.setRpcTarget = function (rpcUrl) {
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 571968b65..a76d5cd86 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -29,9 +29,10 @@ module.exports = class MetamaskController extends EventEmitter {
super()
this.opts = opts
this.state = { network: 'loading' }
+ let initState = opts.initState || {}
// observable state store
- this.store = new ObservableStore(opts.initState)
+ this.store = new ObservableStore(initState)
// config manager
this.configManager = new ConfigManager({
@@ -41,7 +42,7 @@ module.exports = class MetamaskController extends EventEmitter {
// rpc provider
this.provider = this.initializeProvider(opts)
- this.provider.on('block', this.processBlock.bind(this))
+ this.provider.on('block', this.logBlock.bind(this))
this.provider.on('error', this.getNetwork.bind(this))
// eth data query tools
@@ -50,6 +51,7 @@ module.exports = class MetamaskController extends EventEmitter {
// key mgmt
this.keyringController = new KeyringController({
+ initState: initState.KeyringController,
ethStore: this.ethStore,
configManager: this.configManager,
getNetwork: this.getStateNetwork.bind(this),
@@ -97,6 +99,9 @@ module.exports = class MetamaskController extends EventEmitter {
this.keyringController.on('update', this.sendUpdate.bind(this))
this.txManager.on('update', this.sendUpdate.bind(this))
this.messageManager.on('update', this.sendUpdate.bind(this))
+ this.keyringController.store.subscribe((state) => {
+ this.store.updateState({ KeyringController: state })
+ })
}
//
@@ -139,9 +144,7 @@ module.exports = class MetamaskController extends EventEmitter {
const result = { selectedAccount: undefined }
try {
result.selectedAccount = state.config.selectedAccount
- } catch (_) {
- // thats fine, im sure it will be there next time...
- }
+ } catch (_) {}
return result
}
@@ -162,7 +165,9 @@ module.exports = class MetamaskController extends EventEmitter {
this.txManager.getState(),
this.messageManager.getState(),
keyringControllerState,
- this.noticeController.getState(), {
+ this.noticeController.getState(),
+ {
+ shapeShiftTxList: this.configManager.getShapeShiftTxList(),
lostAccounts: this.configManager.getLostAccounts(),
}
)
@@ -268,6 +273,13 @@ module.exports = class MetamaskController extends EventEmitter {
}
}
+ setupPublicConfig (outStream) {
+ pipe(
+ this.publicConfigStore,
+ outStream
+ )
+ }
+
sendUpdate () {
this.getState()
.then((state) => {
@@ -388,31 +400,90 @@ module.exports = class MetamaskController extends EventEmitter {
}).catch((err) => cb(err))
}
- setupPublicConfig (outStream) {
- pipe(
- this.publicConfigStore,
- outStream
- )
+
+ markAccountsFound (cb) {
+ this.configManager.setLostAccounts([])
+ this.sendUpdate()
+ cb(null, this.getState())
}
- // Log blocks
- processBlock (block) {
- if (global.METAMASK_DEBUG) {
- console.log(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`)
+ // Migrate Old Vault If Any
+ // @string password
+ //
+ // returns Promise()
+ //
+ // Temporary step used when logging in.
+ // Checks if old style (pre-3.0.0) Metamask Vault exists.
+ // If so, persists that vault in the new vault format
+ // with the provided password, so the other unlock steps
+ // may be completed without interruption.
+ migrateOldVaultIfAny (password) {
+
+ if (!this.checkIfShouldMigrate()) {
+ return Promise.resolve(password)
}
- this.verifyNetwork()
+
+ const keyringController = this.keyringController
+
+ return this.idStoreMigrator.migratedVaultForPassword(password)
+ .then(this.restoreOldVaultAccounts.bind(this))
+ .then(this.restoreOldLostAccounts.bind(this))
+ .then(keyringController.persistAllKeyrings.bind(keyringController, password))
+ .then(() => password)
}
- verifyNetwork () {
- // Check network when restoring connectivity:
- if (this.state.network === 'loading') {
- this.getNetwork()
+ checkIfShouldMigrate() {
+ return !!this.configManager.getWallet() && !this.configManager.getVault()
+ }
+
+ restoreOldVaultAccounts(migratorOutput) {
+ const { serialized } = migratorOutput
+ return this.keyringController.restoreKeyring(serialized)
+ .then(() => migratorOutput)
+ }
+
+ restoreOldLostAccounts(migratorOutput) {
+ const { lostAccounts } = migratorOutput
+ if (lostAccounts) {
+ this.configManager.setLostAccounts(lostAccounts.map(acct => acct.address))
+ return this.importLostAccounts(migratorOutput)
}
+ return Promise.resolve(migratorOutput)
}
- // config
+ // IMPORT LOST ACCOUNTS
+ // @Object with key lostAccounts: @Array accounts <{ address, privateKey }>
+ // Uses the array's private keys to create a new Simple Key Pair keychain
+ // and add it to the keyring controller.
+ importLostAccounts ({ lostAccounts }) {
+ const privKeys = lostAccounts.map(acct => acct.privateKey)
+ return this.keyringController.restoreKeyring({
+ type: 'Simple Key Pair',
+ data: privKeys,
+ })
+ }
+
+ //
+ // disclaimer
//
+ agreeToDisclaimer (cb) {
+ try {
+ this.configManager.setConfirmedDisclaimer(true)
+ cb()
+ } catch (err) {
+ cb(err)
+ }
+ }
+
+ resetDisclaimer () {
+ try {
+ this.configManager.setConfirmedDisclaimer(false)
+ } catch (e) {
+ console.error(e)
+ }
+ }
+
setTOSHash (hash) {
try {
this.configManager.setTOSHash(hash)
@@ -433,23 +504,16 @@ module.exports = class MetamaskController extends EventEmitter {
}
}
- // disclaimer
-
- agreeToDisclaimer (cb) {
- try {
- this.configManager.setConfirmedDisclaimer(true)
- cb()
- } catch (err) {
- cb(err)
- }
- }
+ //
+ // config
+ //
- resetDisclaimer () {
- try {
- this.configManager.setConfirmedDisclaimer(false)
- } catch (e) {
- console.error(e)
+ // Log blocks
+ logBlock (block) {
+ if (global.METAMASK_DEBUG) {
+ console.log(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`)
}
+ this.verifyNetwork()
}
setCurrentFiat (fiat, cb) {
@@ -477,24 +541,6 @@ module.exports = class MetamaskController extends EventEmitter {
}, 300000)
}
- // called from popup
- setRpcTarget (rpcTarget) {
- this.configManager.setRpcTarget(rpcTarget)
- extension.runtime.reload()
- this.getNetwork()
- }
-
- setProviderType (type) {
- this.configManager.setProviderType(type)
- extension.runtime.reload()
- this.getNetwork()
- }
-
- useEtherscanProvider () {
- this.configManager.useEtherscanProvider()
- extension.runtime.reload()
- }
-
buyEth (address, amount) {
if (!amount) amount = '5'
@@ -514,25 +560,6 @@ module.exports = class MetamaskController extends EventEmitter {
this.configManager.createShapeShiftTx(depositAddress, depositType)
}
- getNetwork (err) {
- if (err) {
- this.state.network = 'loading'
- this.sendUpdate()
- }
-
- this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
- if (err) {
- this.state.network = 'loading'
- return this.sendUpdate()
- }
- if (global.METAMASK_DEBUG) {
- console.log('web3.getNetwork returned ' + network)
- }
- this.state.network = network
- this.sendUpdate()
- })
- }
-
setGasMultiplier (gasMultiplier, cb) {
try {
this.configManager.setGasMultiplier(gasMultiplier)
@@ -542,69 +569,55 @@ module.exports = class MetamaskController extends EventEmitter {
}
}
- getStateNetwork () {
- return this.state.network
- }
-
- markAccountsFound (cb) {
- this.configManager.setLostAccounts([])
- this.sendUpdate()
- cb(null, this.getState())
- }
-
- // Migrate Old Vault If Any
- // @string password
//
- // returns Promise()
+ // network
//
- // Temporary step used when logging in.
- // Checks if old style (pre-3.0.0) Metamask Vault exists.
- // If so, persists that vault in the new vault format
- // with the provided password, so the other unlock steps
- // may be completed without interruption.
- migrateOldVaultIfAny (password) {
- if (!this.checkIfShouldMigrate()) {
- return Promise.resolve(password)
+ verifyNetwork () {
+ // Check network when restoring connectivity:
+ if (this.state.network === 'loading') {
+ this.getNetwork()
}
+ }
- const keyringController = this.keyringController
+ setRpcTarget (rpcTarget) {
+ this.configManager.setRpcTarget(rpcTarget)
+ extension.runtime.reload()
+ this.getNetwork()
+ }
- return this.idStoreMigrator.migratedVaultForPassword(password)
- .then(this.restoreOldVaultAccounts.bind(this))
- .then(this.restoreOldLostAccounts.bind(this))
- .then(keyringController.persistAllKeyrings.bind(keyringController, password))
- .then(() => password)
+ setProviderType (type) {
+ this.configManager.setProviderType(type)
+ extension.runtime.reload()
+ this.getNetwork()
}
- checkIfShouldMigrate() {
- return !!this.configManager.getWallet() && !this.configManager.getVault()
+ useEtherscanProvider () {
+ this.configManager.useEtherscanProvider()
+ extension.runtime.reload()
}
- restoreOldVaultAccounts(migratorOutput) {
- const { serialized } = migratorOutput
- return this.keyringController.restoreKeyring(serialized)
- .then(() => migratorOutput)
+ getStateNetwork () {
+ return this.state.network
}
- restoreOldLostAccounts(migratorOutput) {
- const { lostAccounts } = migratorOutput
- if (lostAccounts) {
- this.configManager.setLostAccounts(lostAccounts.map(acct => acct.address))
- return this.importLostAccounts(migratorOutput)
+ getNetwork (err) {
+ if (err) {
+ this.state.network = 'loading'
+ this.sendUpdate()
}
- return Promise.resolve(migratorOutput)
- }
- // IMPORT LOST ACCOUNTS
- // @Object with key lostAccounts: @Array accounts <{ address, privateKey }>
- // Uses the array's private keys to create a new Simple Key Pair keychain
- // and add it to the keyring controller.
- importLostAccounts ({ lostAccounts }) {
- const privKeys = lostAccounts.map(acct => acct.privateKey)
- return this.keyringController.restoreKeyring({
- type: 'Simple Key Pair',
- data: privKeys,
+ this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
+ if (err) {
+ this.state.network = 'loading'
+ return this.sendUpdate()
+ }
+ if (global.METAMASK_DEBUG) {
+ console.log('web3.getNetwork returned ' + network)
+ }
+ this.state.network = network
+ this.sendUpdate()
})
}
+
}
diff --git a/app/scripts/migrations/005.js b/app/scripts/migrations/005.js
new file mode 100644
index 000000000..65f62a861
--- /dev/null
+++ b/app/scripts/migrations/005.js
@@ -0,0 +1,41 @@
+const version = 5
+
+/*
+
+This migration moves state from the flat state trie into KeyringController substate
+
+*/
+
+const extend = require('xtend')
+
+module.exports = {
+ version,
+
+ migrate: function (versionedData) {
+ versionedData.meta.version = version
+ try {
+ const state = versionedData.data
+ const newState = selectSubstateForKeyringController(state)
+ versionedData.data = newState
+ } catch (err) {
+ console.warn('MetaMask Migration #5' + err.stack)
+ }
+ return Promise.resolve(versionedData)
+ },
+}
+
+function selectSubstateForKeyringController (state) {
+ const config = state.config
+ const newState = extend(state, {
+ KeyringController: {
+ vault: state.vault,
+ selectedAccount: config.selectedAccount,
+ walletNicknames: state.walletNicknames,
+ },
+ })
+ delete newState.vault
+ delete newState.walletNicknames
+ delete newState.config.selectedAccount
+
+ return newState
+}
diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js
index d2ac221b9..a7ce745e7 100644
--- a/app/scripts/migrations/index.js
+++ b/app/scripts/migrations/index.js
@@ -15,4 +15,5 @@ module.exports = [
require('./002'),
require('./003'),
require('./004'),
+ require('./005'),
]