Still needs linting fixes, probably bugs, this commit should be used as a draft of what a separation of these concerns might look like.feature/default_network_editable
parent
cbcc0438cb
commit
9ed3c676ec
@ -0,0 +1,255 @@ |
||||
const extend = require('xtend') |
||||
const EthStore = require('eth-store') |
||||
const MetaMaskProvider = require('web3-provider-engine/zero.js') |
||||
const IdentityStore = require('./lib/idStore') |
||||
const configManager = require('./lib/config-manager-singleton') |
||||
const messageManager = require('./lib/message-manager') |
||||
const HostStore = require('./lib/remote-store.js').HostStore |
||||
const Web3 = require('web3') |
||||
|
||||
|
||||
module.exports = BackgroundController |
||||
|
||||
class BackgroundController { |
||||
|
||||
constructor (opts) { |
||||
this.idStore = new IdentityStore() |
||||
this.configManager = configManager |
||||
this.messageManager = messageManager |
||||
this.provider = this.initializeProvider(opts) |
||||
this.ethStore = new EthStore(this.provider) |
||||
this.idStore.setStore(this.ethStore) |
||||
this.publicConfigStore = this.initPublicConfigStore() |
||||
} |
||||
|
||||
get state () { |
||||
return extend( |
||||
this.ethStore.getState(), |
||||
this.idStore.getState(), |
||||
this.configManager.getConfig() |
||||
) |
||||
} |
||||
|
||||
get api () { |
||||
const idStore = this.idStore |
||||
|
||||
return { |
||||
getState: function (cb) { cb(null, this.state) }, |
||||
setRpcTarget: setRpcTarget, |
||||
setProviderType: setProviderType, |
||||
useEtherscanProvider: useEtherscanProvider, |
||||
agreeToDisclaimer: agreeToDisclaimer, |
||||
// forward directly to idStore
|
||||
createNewVault: idStore.createNewVault.bind(idStore), |
||||
recoverFromSeed: idStore.recoverFromSeed.bind(idStore), |
||||
submitPassword: idStore.submitPassword.bind(idStore), |
||||
setSelectedAddress: idStore.setSelectedAddress.bind(idStore), |
||||
approveTransaction: idStore.approveTransaction.bind(idStore), |
||||
cancelTransaction: idStore.cancelTransaction.bind(idStore), |
||||
signMessage: idStore.signMessage.bind(idStore), |
||||
cancelMessage: idStore.cancelMessage.bind(idStore), |
||||
setLocked: idStore.setLocked.bind(idStore), |
||||
clearSeedWordCache: idStore.clearSeedWordCache.bind(idStore), |
||||
exportAccount: idStore.exportAccount.bind(idStore), |
||||
revealAccount: idStore.revealAccount.bind(idStore), |
||||
saveAccountLabel: idStore.saveAccountLabel.bind(idStore), |
||||
tryPassword: idStore.tryPassword.bind(idStore), |
||||
recoverSeed: idStore.recoverSeed.bind(idStore), |
||||
} |
||||
} |
||||
|
||||
setupProviderConnection (stream, originDomain) { |
||||
stream.on('data', this.onRpcRequest.bind(this, stream, originDomain)) |
||||
} |
||||
|
||||
onRpcRequest (stream, originDomain, request) { |
||||
var payloads = Array.isArray(request) ? request : [request] |
||||
payloads.forEach(function (payload) { |
||||
// Append origin to rpc payload
|
||||
payload.origin = originDomain |
||||
// Append origin to signature request
|
||||
if (payload.method === 'eth_sendTransaction') { |
||||
payload.params[0].origin = originDomain |
||||
} else if (payload.method === 'eth_sign') { |
||||
payload.params.push({ origin: originDomain }) |
||||
} |
||||
}) |
||||
|
||||
// handle rpc request
|
||||
this.provider.sendAsync(request, function onPayloadHandled (err, response) { |
||||
if (err) { |
||||
return logger(err) |
||||
} |
||||
logger(null, request, response) |
||||
try { |
||||
stream.write(response) |
||||
} catch (err) { |
||||
logger(err) |
||||
} |
||||
}) |
||||
|
||||
function logger (err, request, response) { |
||||
if (err) return console.error(err.stack) |
||||
if (!request.isMetamaskInternal) { |
||||
console.log(`RPC (${originDomain}):`, request, '->', response) |
||||
if (response.error) console.error('Error in RPC response:\n' + response.error.message) |
||||
} |
||||
} |
||||
} |
||||
|
||||
sendUpdate () { |
||||
this.remote.sendUpdate(this.state) |
||||
} |
||||
|
||||
initializeProvider (opts) { |
||||
const idStore = this.idStore |
||||
|
||||
var providerOpts = { |
||||
rpcUrl: configManager.getCurrentRpcAddress(), |
||||
// account mgmt
|
||||
getAccounts: function (cb) { |
||||
var selectedAddress = idStore.getSelectedAddress() |
||||
var result = selectedAddress ? [selectedAddress] : [] |
||||
cb(null, result) |
||||
}, |
||||
// tx signing
|
||||
approveTransaction: this.newUnsignedTransaction, |
||||
signTransaction: idStore.signTransaction.bind(idStore), |
||||
// msg signing
|
||||
approveMessage: this.newUnsignedMessage, |
||||
signMessage: idStore.signMessage.bind(idStore), |
||||
} |
||||
|
||||
var provider = MetaMaskProvider(providerOpts) |
||||
var web3 = new Web3(provider) |
||||
idStore.web3 = web3 |
||||
idStore.getNetwork() |
||||
|
||||
provider.on('block', this.processBlock) |
||||
provider.on('error', idStore.getNetwork.bind(idStore)) |
||||
|
||||
return provider |
||||
} |
||||
|
||||
initPublicConfigStore () { |
||||
// get init state
|
||||
var initPublicState = extend( |
||||
idStoreToPublic(this.idStore.getState()), |
||||
configToPublic(this.configManager.getConfig()) |
||||
) |
||||
|
||||
var publicConfigStore = new HostStore(initPublicState) |
||||
|
||||
// subscribe to changes
|
||||
this.configManager.subscribe(function (state) { |
||||
storeSetFromObj(publicConfigStore, configToPublic(state)) |
||||
}) |
||||
this.idStore.on('update', function (state) { |
||||
storeSetFromObj(publicConfigStore, idStoreToPublic(state)) |
||||
}) |
||||
|
||||
// idStore substate
|
||||
function idStoreToPublic (state) { |
||||
return { |
||||
selectedAddress: state.selectedAddress, |
||||
} |
||||
} |
||||
// config substate
|
||||
function configToPublic (state) { |
||||
return { |
||||
provider: state.provider, |
||||
} |
||||
} |
||||
// dump obj into store
|
||||
function storeSetFromObj (store, obj) { |
||||
Object.keys(obj).forEach(function (key) { |
||||
store.set(key, obj[key]) |
||||
}) |
||||
} |
||||
|
||||
return publicConfigStore |
||||
} |
||||
|
||||
newUnsignedTransaction (txParams, onTxDoneCb) { |
||||
const idStore = this.idStore |
||||
var state = idStore.getState() |
||||
|
||||
// It's locked
|
||||
if (!state.isUnlocked) { |
||||
this.opts.unlockAccountMessage() |
||||
idStore.addUnconfirmedTransaction(txParams, onTxDoneCb, noop) |
||||
|
||||
// It's unlocked
|
||||
} else { |
||||
idStore.addUnconfirmedTransaction(txParams, onTxDoneCb, (err, txData) => { |
||||
if (err) return onTxDoneCb(err) |
||||
this.opts.showUnconfirmedTx(txParams, txData, onTxDoneCb) |
||||
}) |
||||
} |
||||
} |
||||
|
||||
newUnsignedMessage(msgParams, cb) { |
||||
var state = this.idStore.getState() |
||||
if (!state.isUnlocked) { |
||||
this.opts.unlockAccountMessage() |
||||
} else { |
||||
this.addUnconfirmedMsg(msgParams, cb) |
||||
} |
||||
} |
||||
|
||||
addUnconfirmedMessage (msgParams, cb) { |
||||
const idStore = this.idStore |
||||
const msgId = idStore.addUnconfirmedMessage(msgParams, cb) |
||||
this.opts.showUnconfirmedMessage(msgParams, msgId) |
||||
} |
||||
|
||||
setupPublicConfig (stream) { |
||||
var storeStream = publicConfigStore.createStream() |
||||
stream.pipe(storeStream).pipe(stream) |
||||
} |
||||
|
||||
// Log blocks
|
||||
processBlock (block) { |
||||
console.log(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`) |
||||
this.verifyNetwork() |
||||
} |
||||
|
||||
verifyNetwork () { |
||||
// Check network when restoring connectivity:
|
||||
if (this.idStore._currentState.network === 'loading') { |
||||
this.idStore.getNetwork() |
||||
} |
||||
} |
||||
} |
||||
|
||||
// config
|
||||
//
|
||||
|
||||
function agreeToDisclaimer (cb) { |
||||
try { |
||||
configManager.setConfirmed(true) |
||||
cb() |
||||
} catch (e) { |
||||
cb(e) |
||||
} |
||||
} |
||||
|
||||
// called from popup
|
||||
function setRpcTarget (rpcTarget) { |
||||
configManager.setRpcTarget(rpcTarget) |
||||
chrome.runtime.reload() |
||||
idStore.getNetwork() |
||||
} |
||||
|
||||
function setProviderType (type) { |
||||
configManager.setProviderType(type) |
||||
chrome.runtime.reload() |
||||
idStore.getNetwork() |
||||
} |
||||
|
||||
function useEtherscanProvider () { |
||||
configManager.useEtherscanProvider() |
||||
chrome.runtime.reload() |
||||
} |
||||
|
||||
function noop () {} |
Loading…
Reference in new issue