|
|
@ -1,12 +1,14 @@ |
|
|
|
const ethUtil = require('ethereumjs-util') |
|
|
|
const ethUtil = require('ethereumjs-util') |
|
|
|
|
|
|
|
const BN = ethUtil.BN |
|
|
|
const bip39 = require('bip39') |
|
|
|
const bip39 = require('bip39') |
|
|
|
const EventEmitter = require('events').EventEmitter |
|
|
|
const EventEmitter = require('events').EventEmitter |
|
|
|
|
|
|
|
const ObservableStore = require('obs-store') |
|
|
|
const filter = require('promise-filter') |
|
|
|
const filter = require('promise-filter') |
|
|
|
const encryptor = require('browser-passworder') |
|
|
|
const encryptor = require('browser-passworder') |
|
|
|
|
|
|
|
const createId = require('./lib/random-id') |
|
|
|
const normalize = require('./lib/sig-util').normalize |
|
|
|
const normalizeAddress = require('./lib/sig-util').normalize |
|
|
|
const messageManager = require('./lib/message-manager') |
|
|
|
const messageManager = require('./lib/message-manager') |
|
|
|
const BN = ethUtil.BN |
|
|
|
function noop () {} |
|
|
|
|
|
|
|
|
|
|
|
// Keyrings:
|
|
|
|
// Keyrings:
|
|
|
|
const SimpleKeyring = require('./keyrings/simple') |
|
|
|
const SimpleKeyring = require('./keyrings/simple') |
|
|
@ -16,9 +18,8 @@ const keyringTypes = [ |
|
|
|
HdKeyring, |
|
|
|
HdKeyring, |
|
|
|
] |
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
const createId = require('./lib/random-id') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = class KeyringController extends EventEmitter { |
|
|
|
class KeyringController extends EventEmitter { |
|
|
|
|
|
|
|
|
|
|
|
// PUBLIC METHODS
|
|
|
|
// PUBLIC METHODS
|
|
|
|
//
|
|
|
|
//
|
|
|
@ -29,6 +30,8 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
|
|
|
|
|
|
|
|
constructor (opts) { |
|
|
|
constructor (opts) { |
|
|
|
super() |
|
|
|
super() |
|
|
|
|
|
|
|
const initState = opts.initState || {} |
|
|
|
|
|
|
|
this.store = new ObservableStore(initState) |
|
|
|
this.configManager = opts.configManager |
|
|
|
this.configManager = opts.configManager |
|
|
|
this.ethStore = opts.ethStore |
|
|
|
this.ethStore = opts.ethStore |
|
|
|
this.encryptor = encryptor |
|
|
|
this.encryptor = encryptor |
|
|
@ -71,29 +74,31 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
// in this class, but will need to be Promisified when we move our
|
|
|
|
// in this class, but will need to be Promisified when we move our
|
|
|
|
// persistence to an async model.
|
|
|
|
// persistence to an async model.
|
|
|
|
getState () { |
|
|
|
getState () { |
|
|
|
const configManager = this.configManager |
|
|
|
return Promise.all(this.keyrings.map(this.displayForKeyring)) |
|
|
|
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)) |
|
|
|
|
|
|
|
.then((displayKeyrings) => { |
|
|
|
.then((displayKeyrings) => { |
|
|
|
|
|
|
|
const state = this.store.getState() |
|
|
|
|
|
|
|
// old wallet
|
|
|
|
|
|
|
|
const wallet = this.configManager.getWallet() |
|
|
|
return { |
|
|
|
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(), |
|
|
|
seedWords: this.configManager.getSeedWords(), |
|
|
|
isInitialized: (!!wallet || !!vault), |
|
|
|
|
|
|
|
isUnlocked: Boolean(this.password), |
|
|
|
|
|
|
|
isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(), |
|
|
|
isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(), |
|
|
|
unconfMsgs: messageManager.unconfirmedMsgs(), |
|
|
|
|
|
|
|
messages: messageManager.getMsgList(), |
|
|
|
|
|
|
|
selectedAccount: address, |
|
|
|
|
|
|
|
shapeShiftTxList: this.configManager.getShapeShiftTxList(), |
|
|
|
|
|
|
|
currentFiat: this.configManager.getCurrentFiat(), |
|
|
|
currentFiat: this.configManager.getCurrentFiat(), |
|
|
|
conversionRate: this.configManager.getConversionRate(), |
|
|
|
conversionRate: this.configManager.getConversionRate(), |
|
|
|
conversionDate: this.configManager.getConversionDate(), |
|
|
|
conversionDate: this.configManager.getConversionDate(), |
|
|
|
keyringTypes: this.keyringTypes.map(krt => krt.type), |
|
|
|
// messageManager
|
|
|
|
identities: this.identities, |
|
|
|
unconfMsgs: messageManager.unconfirmedMsgs(), |
|
|
|
keyrings: displayKeyrings, |
|
|
|
messages: messageManager.getMsgList(), |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
@ -146,8 +151,8 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
.then((accounts) => { |
|
|
|
.then((accounts) => { |
|
|
|
const firstAccount = accounts[0] |
|
|
|
const firstAccount = accounts[0] |
|
|
|
if (!firstAccount) throw new Error('KeyringController - First Account not found.') |
|
|
|
if (!firstAccount) throw new Error('KeyringController - First Account not found.') |
|
|
|
const hexAccount = normalize(firstAccount) |
|
|
|
const hexAccount = normalizeAddress(firstAccount) |
|
|
|
this.configManager.setSelectedAccount(hexAccount) |
|
|
|
this.setSelectedAccount(hexAccount) |
|
|
|
return this.setupAccounts(accounts) |
|
|
|
return this.setupAccounts(accounts) |
|
|
|
}) |
|
|
|
}) |
|
|
|
.then(this.persistAllKeyrings.bind(this, password)) |
|
|
|
.then(this.persistAllKeyrings.bind(this, password)) |
|
|
@ -233,9 +238,9 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
//
|
|
|
|
//
|
|
|
|
// Sets the state's `selectedAccount` value
|
|
|
|
// Sets the state's `selectedAccount` value
|
|
|
|
// to the specified address.
|
|
|
|
// to the specified address.
|
|
|
|
setSelectedAccount (address) { |
|
|
|
setSelectedAccount (account) { |
|
|
|
var addr = normalize(address) |
|
|
|
var address = normalizeAddress(account) |
|
|
|
this.configManager.setSelectedAccount(addr) |
|
|
|
this.store.updateState({ selectedAccount: address }) |
|
|
|
return this.fullUpdate() |
|
|
|
return this.fullUpdate() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -247,11 +252,19 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
//
|
|
|
|
//
|
|
|
|
// Persists a nickname equal to `label` for the specified account.
|
|
|
|
// Persists a nickname equal to `label` for the specified account.
|
|
|
|
saveAccountLabel (account, label) { |
|
|
|
saveAccountLabel (account, label) { |
|
|
|
const address = normalize(account) |
|
|
|
try { |
|
|
|
const configManager = this.configManager |
|
|
|
const hexAddress = normalizeAddress(account) |
|
|
|
configManager.setNicknameForWallet(address, label) |
|
|
|
// update state on diskStore
|
|
|
|
this.identities[address].name = label |
|
|
|
const state = this.store.getState() |
|
|
|
return Promise.resolve(label) |
|
|
|
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
|
|
|
|
// Export Account
|
|
|
@ -267,7 +280,7 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
try { |
|
|
|
try { |
|
|
|
return this.getKeyringForAccount(address) |
|
|
|
return this.getKeyringForAccount(address) |
|
|
|
.then((keyring) => { |
|
|
|
.then((keyring) => { |
|
|
|
return keyring.exportAccount(normalize(address)) |
|
|
|
return keyring.exportAccount(normalizeAddress(address)) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
return Promise.reject(e) |
|
|
|
return Promise.reject(e) |
|
|
@ -281,7 +294,7 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
// TX Manager to update the state after signing
|
|
|
|
// TX Manager to update the state after signing
|
|
|
|
|
|
|
|
|
|
|
|
signTransaction (ethTx, _fromAddress) { |
|
|
|
signTransaction (ethTx, _fromAddress) { |
|
|
|
const fromAddress = normalize(_fromAddress) |
|
|
|
const fromAddress = normalizeAddress(_fromAddress) |
|
|
|
return this.getKeyringForAccount(fromAddress) |
|
|
|
return this.getKeyringForAccount(fromAddress) |
|
|
|
.then((keyring) => { |
|
|
|
.then((keyring) => { |
|
|
|
return keyring.signTransaction(fromAddress, ethTx) |
|
|
|
return keyring.signTransaction(fromAddress, ethTx) |
|
|
@ -354,7 +367,7 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
delete msgParams.metamaskId |
|
|
|
delete msgParams.metamaskId |
|
|
|
const approvalCb = this._unconfMsgCbs[msgId] || noop |
|
|
|
const approvalCb = this._unconfMsgCbs[msgId] || noop |
|
|
|
|
|
|
|
|
|
|
|
const address = normalize(msgParams.from) |
|
|
|
const address = normalizeAddress(msgParams.from) |
|
|
|
return this.getKeyringForAccount(address) |
|
|
|
return this.getKeyringForAccount(address) |
|
|
|
.then((keyring) => { |
|
|
|
.then((keyring) => { |
|
|
|
return keyring.signMessage(address, msgParams.data) |
|
|
|
return keyring.signMessage(address, msgParams.data) |
|
|
@ -392,8 +405,8 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
.then((accounts) => { |
|
|
|
.then((accounts) => { |
|
|
|
const firstAccount = accounts[0] |
|
|
|
const firstAccount = accounts[0] |
|
|
|
if (!firstAccount) throw new Error('KeyringController - No account found on keychain.') |
|
|
|
if (!firstAccount) throw new Error('KeyringController - No account found on keychain.') |
|
|
|
const hexAccount = normalize(firstAccount) |
|
|
|
const hexAccount = normalizeAddress(firstAccount) |
|
|
|
this.configManager.setSelectedAccount(hexAccount) |
|
|
|
this.setSelectedAccount(hexAccount) |
|
|
|
this.emit('newAccount', hexAccount) |
|
|
|
this.emit('newAccount', hexAccount) |
|
|
|
return this.setupAccounts(accounts) |
|
|
|
return this.setupAccounts(accounts) |
|
|
|
}) |
|
|
|
}) |
|
|
@ -429,7 +442,7 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
if (!account) { |
|
|
|
if (!account) { |
|
|
|
throw new Error('Problem loading account.') |
|
|
|
throw new Error('Problem loading account.') |
|
|
|
} |
|
|
|
} |
|
|
|
const address = normalize(account) |
|
|
|
const address = normalizeAddress(account) |
|
|
|
this.ethStore.addAccount(address) |
|
|
|
this.ethStore.addAccount(address) |
|
|
|
return this.createNickname(address) |
|
|
|
return this.createNickname(address) |
|
|
|
} |
|
|
|
} |
|
|
@ -441,10 +454,11 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
//
|
|
|
|
//
|
|
|
|
// Takes an address, and assigns it an incremented nickname, persisting it.
|
|
|
|
// Takes an address, and assigns it an incremented nickname, persisting it.
|
|
|
|
createNickname (address) { |
|
|
|
createNickname (address) { |
|
|
|
const hexAddress = normalize(address) |
|
|
|
const hexAddress = normalizeAddress(address) |
|
|
|
var i = Object.keys(this.identities).length |
|
|
|
const currentIdentityCount = Object.keys(this.identities).length + 1 |
|
|
|
const oldNickname = this.configManager.nicknameForWallet(address) |
|
|
|
const nicknames = this.store.getState().walletNicknames || {} |
|
|
|
const name = oldNickname || `Account ${++i}` |
|
|
|
const existingNickname = nicknames[hexAddress] |
|
|
|
|
|
|
|
const name = existingNickname || `Account ${currentIdentityCount}` |
|
|
|
this.identities[hexAddress] = { |
|
|
|
this.identities[hexAddress] = { |
|
|
|
address: hexAddress, |
|
|
|
address: hexAddress, |
|
|
|
name, |
|
|
|
name, |
|
|
@ -479,7 +493,7 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
return this.encryptor.encrypt(this.password, serializedKeyrings) |
|
|
|
return this.encryptor.encrypt(this.password, serializedKeyrings) |
|
|
|
}) |
|
|
|
}) |
|
|
|
.then((encryptedString) => { |
|
|
|
.then((encryptedString) => { |
|
|
|
this.configManager.setVault(encryptedString) |
|
|
|
this.store.updateState({ vault: encryptedString }) |
|
|
|
return true |
|
|
|
return true |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
@ -492,7 +506,7 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
// Attempts to unlock the persisted encrypted storage,
|
|
|
|
// Attempts to unlock the persisted encrypted storage,
|
|
|
|
// initializing the persisted keyrings to RAM.
|
|
|
|
// initializing the persisted keyrings to RAM.
|
|
|
|
unlockKeyrings (password) { |
|
|
|
unlockKeyrings (password) { |
|
|
|
const encryptedVault = this.configManager.getVault() |
|
|
|
const encryptedVault = this.store.getState().vault |
|
|
|
if (!encryptedVault) { |
|
|
|
if (!encryptedVault) { |
|
|
|
throw new Error('Cannot unlock without a previous vault.') |
|
|
|
throw new Error('Cannot unlock without a previous vault.') |
|
|
|
} |
|
|
|
} |
|
|
@ -572,7 +586,7 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
// Returns the currently initialized keyring that manages
|
|
|
|
// Returns the currently initialized keyring that manages
|
|
|
|
// the specified `address` if one exists.
|
|
|
|
// the specified `address` if one exists.
|
|
|
|
getKeyringForAccount (address) { |
|
|
|
getKeyringForAccount (address) { |
|
|
|
const hexed = normalize(address) |
|
|
|
const hexed = normalizeAddress(address) |
|
|
|
|
|
|
|
|
|
|
|
return Promise.all(this.keyrings.map((keyring) => { |
|
|
|
return Promise.all(this.keyrings.map((keyring) => { |
|
|
|
return Promise.all([ |
|
|
|
return Promise.all([ |
|
|
@ -581,7 +595,7 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
]) |
|
|
|
]) |
|
|
|
})) |
|
|
|
})) |
|
|
|
.then(filter((candidate) => { |
|
|
|
.then(filter((candidate) => { |
|
|
|
const accounts = candidate[1].map(normalize) |
|
|
|
const accounts = candidate[1].map(normalizeAddress) |
|
|
|
return accounts.includes(hexed) |
|
|
|
return accounts.includes(hexed) |
|
|
|
})) |
|
|
|
})) |
|
|
|
.then((winners) => { |
|
|
|
.then((winners) => { |
|
|
@ -639,10 +653,9 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
|
|
|
|
|
|
|
|
this.keyrings = [] |
|
|
|
this.keyrings = [] |
|
|
|
this.identities = {} |
|
|
|
this.identities = {} |
|
|
|
this.configManager.setSelectedAccount() |
|
|
|
this.setSelectedAccount() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = KeyringController |
|
|
|
function noop () {} |
|
|
|
|
|
|
|