From fa7e4665594525256b846de93bdd46115a3a53a7 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 24 Jun 2016 15:55:11 -0700 Subject: Rename background-controller metamask-controller --- app/scripts/metamask-controller.js | 255 +++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 app/scripts/metamask-controller.js (limited to 'app/scripts/metamask-controller.js') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js new file mode 100644 index 000000000..aef280310 --- /dev/null +++ b/app/scripts/metamask-controller.js @@ -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 messageManager = require('./lib/message-manager') +const HostStore = require('./lib/remote-store.js').HostStore +const Web3 = require('web3') +const ConfigManager = require('./lib/config-manager') + +module.exports = MetamaskController + +class MetamaskController { + + constructor (opts) { + this.configManager = new ConfigManager(opts) + this.idStore = new IdentityStore({ configManager }) + this.messageManager = messageManager + this.provider = this.initializeProvider(opts) + this.ethStore = new EthStore(this.provider) + this.idStore.setStore(this.ethStore) + this.publicConfigStore = this.initPublicConfigStore() + } + + getState () { + return extend( + this.ethStore.getState(), + this.idStore.getState(), + this.configManager.getConfig() + ) + } + + getApi () { + const idStore = this.idStore + + return { + getState: function (cb) { cb(null, this.getState()) }, + setRpcTarget: this.setRpcTarget.bind(this), + setProviderType: this.setProviderType.bind(this), + useEtherscanProvider: this.useEtherscanProvider.bind(this), + agreeToDisclaimer: this.agreeToDisclaimer.bind(this), + // 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.getState()) + } + + initializeProvider (opts) { + const idStore = this.idStore + + var providerOpts = { + rpcUrl: this.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 { + this.configManager.setConfirmed(true) + cb() + } catch (e) { + cb(e) + } + } + + // called from popup + function setRpcTarget (rpcTarget) { + this.configManager.setRpcTarget(rpcTarget) + chrome.runtime.reload() + idStore.getNetwork() + } + + function setProviderType (type) { + this.configManager.setProviderType(type) + chrome.runtime.reload() + idStore.getNetwork() + } + + function useEtherscanProvider () { + this.configManager.useEtherscanProvider() + chrome.runtime.reload() + } + +} + +function noop () {} -- cgit v1.2.3 From 122018a96a1b2b6d9b7eefe150ff76a9de69bdd7 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 24 Jun 2016 16:13:27 -0700 Subject: Fixed tests --- app/scripts/metamask-controller.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'app/scripts/metamask-controller.js') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index aef280310..262c20b96 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -13,11 +13,13 @@ class MetamaskController { constructor (opts) { this.configManager = new ConfigManager(opts) - this.idStore = new IdentityStore({ configManager }) - this.messageManager = messageManager this.provider = this.initializeProvider(opts) this.ethStore = new EthStore(this.provider) - this.idStore.setStore(this.ethStore) + this.idStore = new IdentityStore({ + configManager: this.configManager, + ethStore: this.ethStore, + }) + this.messageManager = messageManager this.publicConfigStore = this.initPublicConfigStore() } @@ -203,7 +205,7 @@ class MetamaskController { } setupPublicConfig (stream) { - var storeStream = publicConfigStore.createStream() + var storeStream = this.publicConfigStore.createStream() stream.pipe(storeStream).pipe(stream) } @@ -223,7 +225,7 @@ class MetamaskController { // config // - function agreeToDisclaimer (cb) { + agreeToDisclaimer (cb) { try { this.configManager.setConfirmed(true) cb() @@ -233,23 +235,22 @@ class MetamaskController { } // called from popup - function setRpcTarget (rpcTarget) { + setRpcTarget (rpcTarget) { this.configManager.setRpcTarget(rpcTarget) chrome.runtime.reload() - idStore.getNetwork() + this.idStore.getNetwork() } - function setProviderType (type) { + setProviderType (type) { this.configManager.setProviderType(type) chrome.runtime.reload() - idStore.getNetwork() + this.idStore.getNetwork() } - function useEtherscanProvider () { + useEtherscanProvider () { this.configManager.useEtherscanProvider() chrome.runtime.reload() } - } function noop () {} -- cgit v1.2.3 From d3e0e7fe45a1dc2159b26155b974ced16548ea44 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 24 Jun 2016 16:46:18 -0700 Subject: Manually debugged refactor --- app/scripts/metamask-controller.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'app/scripts/metamask-controller.js') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 262c20b96..d09b4c5f9 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -7,18 +7,16 @@ const HostStore = require('./lib/remote-store.js').HostStore const Web3 = require('web3') const ConfigManager = require('./lib/config-manager') -module.exports = MetamaskController - -class MetamaskController { +module.exports = class MetamaskController { constructor (opts) { this.configManager = new ConfigManager(opts) - this.provider = this.initializeProvider(opts) - this.ethStore = new EthStore(this.provider) this.idStore = new IdentityStore({ configManager: this.configManager, - ethStore: this.ethStore, }) + this.provider = this.initializeProvider(opts) + this.ethStore = new EthStore(this.provider) + this.idStore.setStore(this.ethStore) this.messageManager = messageManager this.publicConfigStore = this.initPublicConfigStore() } @@ -35,7 +33,7 @@ class MetamaskController { const idStore = this.idStore return { - getState: function (cb) { cb(null, this.getState()) }, + getState: (cb) => { cb(null, this.getState()) }, setRpcTarget: this.setRpcTarget.bind(this), setProviderType: this.setProviderType.bind(this), useEtherscanProvider: this.useEtherscanProvider.bind(this), @@ -99,7 +97,9 @@ class MetamaskController { } sendUpdate () { - this.remote.sendUpdate(this.getState()) + if (this.remote) { + this.remote.sendUpdate(this.getState()) + } } initializeProvider (opts) { @@ -126,7 +126,7 @@ class MetamaskController { idStore.web3 = web3 idStore.getNetwork() - provider.on('block', this.processBlock) + provider.on('block', this.processBlock.bind(this)) provider.on('error', idStore.getNetwork.bind(idStore)) return provider -- cgit v1.2.3 From 60fec24c003605047f3ab7c011a1ee98432b369b Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 24 Jun 2016 17:00:35 -0700 Subject: Debugged by using a real dapp --- app/scripts/metamask-controller.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'app/scripts/metamask-controller.js') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index d09b4c5f9..398086274 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -10,6 +10,7 @@ const ConfigManager = require('./lib/config-manager') module.exports = class MetamaskController { constructor (opts) { + this.opts = opts this.configManager = new ConfigManager(opts) this.idStore = new IdentityStore({ configManager: this.configManager, @@ -108,16 +109,16 @@ module.exports = class MetamaskController { var providerOpts = { rpcUrl: this.configManager.getCurrentRpcAddress(), // account mgmt - getAccounts: function (cb) { + getAccounts: (cb) => { var selectedAddress = idStore.getSelectedAddress() var result = selectedAddress ? [selectedAddress] : [] cb(null, result) }, // tx signing - approveTransaction: this.newUnsignedTransaction, + approveTransaction: this.newUnsignedTransaction.bind(this), signTransaction: idStore.signTransaction.bind(idStore), // msg signing - approveMessage: this.newUnsignedMessage, + approveMessage: this.newUnsignedMessage.bind(this), signMessage: idStore.signMessage.bind(idStore), } -- cgit v1.2.3