From d9cadb9efbd8a38522ce638b8def37c935bb6be0 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 31 Mar 2016 11:40:55 -0700 Subject: [PATCH 1/3] First naive pass at implementing etherscan provider (not working) Committing and pushing to get feedback. --- app/manifest.json | 1 + app/scripts/background.js | 27 ++++++++++++++++++++++----- app/scripts/lib/config-manager.js | 31 ++++++++++++++++++++++--------- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/app/manifest.json b/app/manifest.json index 915295914..be5a06c8d 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,5 +1,6 @@ { "name": "__MSG_appName__", + "short_name": "Metamask", "version": "1.2.1", "manifest_version": 2, "description": "__MSG_appDescription__", diff --git a/app/scripts/background.js b/app/scripts/background.js index 772c1de89..cc137616a 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -7,6 +7,7 @@ const extend = require('xtend') const EthStore = require('eth-store') const PortStream = require('./lib/port-stream.js') const MetaMaskProvider = require('web3-provider-engine/zero.js') +const EtherscanProvider = require('web3-provider-engine/subproviders/etherscan') const IdentityStore = require('./lib/idStore') const createTxNotification = require('./lib/tx-notification.js') const configManager = require('./lib/config-manager-singleton') @@ -36,8 +37,9 @@ function handleEthRpcRequestStream(stream){ // state and network // +var providerConfig = configManager.getProvider() var idStore = new IdentityStore() -var zeroClient = MetaMaskProvider({ +var providerOpts = { rpcUrl: configManager.getCurrentRpcAddress(), getAccounts: function(cb){ var selectedAddress = idStore.getSelectedAddress() @@ -46,14 +48,23 @@ var zeroClient = MetaMaskProvider({ }, approveTransaction: addUnconfirmedTx, signTransaction: idStore.signTransaction.bind(idStore), -}) +} +var provider +switch (providerConfig.type) { + case 'rpc': + provider = MetaMaskProvider(providerOpts) + break + case 'etherscan': + provider = EtherscanProvider(providerOpts) + break +} // log new blocks -zeroClient.on('block', function(block){ +provider.on('block', function(block){ console.log('BLOCK CHANGED:', '#'+block.number.toString('hex'), '0x'+block.hash.toString('hex')) }) -var ethStore = new EthStore(zeroClient) +var ethStore = new EthStore(provider) idStore.setStore(ethStore) function getState(){ @@ -68,7 +79,7 @@ function getState(){ // handle rpc requests function onRpcRequest(remoteStream, payload){ // console.log('MetaMaskPlugin - incoming payload:', payload) - zeroClient.sendAsync(payload, function onPayloadHandled(err, response){ + provider.sendAsync(payload, function onPayloadHandled(err, response){ // provider engine errors are included in response objects if (!payload.isMetamaskInternal) console.log('MetaMaskPlugin - RPC complete:', payload, '->', response) try { @@ -111,6 +122,7 @@ function linkDnode(stream){ var connection = Dnode({ getState: function(cb){ cb(null, getState()) }, setRpcTarget: setRpcTarget, + useEtherscanProvider: useEtherscanProvider, // forward directly to idStore createNewVault: idStore.createNewVault.bind(idStore), recoverFromSeed: idStore.recoverFromSeed.bind(idStore), @@ -179,6 +191,11 @@ function setRpcTarget(rpcTarget){ chrome.runtime.reload() } +function useEtherscanProvider() { + configManager.useEtherscanProvider() + chrome.runtime.reload() +} + // util function jsonParseStream(){ diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js index 682b34637..121ede838 100644 --- a/app/scripts/lib/config-manager.js +++ b/app/scripts/lib/config-manager.js @@ -47,15 +47,6 @@ ConfigManager.prototype.setConfig = function(config) { this.setData(data) } -ConfigManager.prototype.setRpcTarget = function(rpcUrl) { - var config = this.getConfig() - config.provider = { - type: 'rpc', - rpcTarget: rpcUrl, - } - this.setConfig(config) -} - ConfigManager.prototype.getConfig = function() { var data = this.migrator.getData() if ('config' in data) { @@ -70,6 +61,28 @@ ConfigManager.prototype.getConfig = function() { } } +ConfigManager.prototype.setRpcTarget = function(rpcUrl) { + var config = this.getConfig() + config.provider = { + type: 'rpc', + rpcTarget: rpcUrl, + } + this.setConfig(config) +} + +ConfigManager.prototype.useEtherscanProvider = function() { + var config = this.getConfig() + config.provider = { + type: 'etherscan', + } + this.setConfig(config) +} + +ConfigManager.prototype.getProvider = function() { + var config = this.getConfig() + return config.provider +} + ConfigManager.prototype.setData = function(data) { this.migrator.saveData(data) } From 091938a2c5a465582b93a7aff809de126e1319f8 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 31 Mar 2016 12:30:27 -0700 Subject: [PATCH 2/3] Add custom zeroclient that supports etherscan (still not working) The Etherscan Subprovider is not providing some methods we need, such as `eth_getCode`. I'll probably be enhancing it after lunch. --- app/scripts/background.js | 14 ++------- app/scripts/lib/zero.js | 65 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 app/scripts/lib/zero.js diff --git a/app/scripts/background.js b/app/scripts/background.js index cc137616a..14293ab05 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -6,8 +6,7 @@ const combineStreams = require('pumpify') const extend = require('xtend') const EthStore = require('eth-store') const PortStream = require('./lib/port-stream.js') -const MetaMaskProvider = require('web3-provider-engine/zero.js') -const EtherscanProvider = require('web3-provider-engine/subproviders/etherscan') +const MetaMaskProvider = require('./lib/zero.js') const IdentityStore = require('./lib/idStore') const createTxNotification = require('./lib/tx-notification.js') const configManager = require('./lib/config-manager-singleton') @@ -48,16 +47,9 @@ var providerOpts = { }, approveTransaction: addUnconfirmedTx, signTransaction: idStore.signTransaction.bind(idStore), + etherscan: providerConfig.type === 'etherscan', } -var provider -switch (providerConfig.type) { - case 'rpc': - provider = MetaMaskProvider(providerOpts) - break - case 'etherscan': - provider = EtherscanProvider(providerOpts) - break -} +var provider = MetaMaskProvider(providerOpts) // log new blocks provider.on('block', function(block){ diff --git a/app/scripts/lib/zero.js b/app/scripts/lib/zero.js new file mode 100644 index 000000000..d33f099d3 --- /dev/null +++ b/app/scripts/lib/zero.js @@ -0,0 +1,65 @@ +const ProviderEngine = require('web3-provider-engine/index.js') +const DefaultFixture = require('web3-provider-engine/subproviders/default-fixture.js') +const NonceTrackerSubprovider = require('web3-provider-engine/subproviders/nonce-tracker.js') +const CacheSubprovider = require('web3-provider-engine/subproviders/cache.js') +const FilterSubprovider = require('web3-provider-engine/subproviders/filters.js') +const HookedWalletSubprovider = require('web3-provider-engine/subproviders/hooked-wallet.js') +const RpcSubprovider = require('web3-provider-engine/subproviders/rpc.js') +const EtherscanSubprovider = require('web3-provider-engine/subproviders/etherscan.js') + + +module.exports = ZeroClientProvider + + +function ZeroClientProvider(opts){ + opts = opts || {} + + var engine = new ProviderEngine() + + // static + var staticSubprovider = new DefaultFixture() + engine.addProvider(staticSubprovider) + + // nonce tracker + engine.addProvider(new NonceTrackerSubprovider()) + + // cache layer + var cacheSubprovider = new CacheSubprovider() + engine.addProvider(cacheSubprovider) + + // filters + var filterSubprovider = new FilterSubprovider() + engine.addProvider(filterSubprovider) + + // id mgmt + var idmgmtSubprovider = new HookedWalletSubprovider({ + getAccounts: opts.getAccounts, + approveTransaction: opts.approveTransaction, + signTransaction: opts.signTransaction, + }) + engine.addProvider(idmgmtSubprovider) + + // data source + var dataProvider + if (!opts.etherscan) { + dataProvider = new RpcSubprovider({ + rpcUrl: opts.rpcUrl || 'https://testrpc.metamask.io/', + }) + } else { + dataProvider = new EtherscanSubprovider() + } + engine.addProvider(dataProvider) + + // // log new blocks + // engine.on('block', function(block){ + // console.log('================================') + // console.log('BLOCK CHANGED:', '#'+block.number.toString('hex'), '0x'+block.hash.toString('hex')) + // console.log('================================') + // }) + + // start polling + engine.start() + + return engine + +} From 8384b035e81d47573f6f3a67045bcd6b3e32287c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 31 Mar 2016 16:23:22 -0700 Subject: [PATCH 3/3] Got etherscan working, bump version New version of provider-engine includes etherscan-subprovider features required to let Metamask use it. Hard coded the new version of `web3-provider-engine` even though it is not live on `npm` yet, because it is a dependency of this branch. I'll deploy to the Chrome store but not merge on Github until that provider-engine is published, because it could break others' dev environments. --- app/manifest.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/manifest.json b/app/manifest.json index be5a06c8d..f37d4663d 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "Metamask", - "version": "1.2.1", + "version": "1.3.0", "manifest_version": 2, "description": "__MSG_appDescription__", "icons": { diff --git a/package.json b/package.json index be61f1d14..83d563633 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "readable-stream": "^2.0.5", "through2": "^2.0.1", "web3": "^0.15.1", - "web3-provider-engine": "^7.0.0", + "web3-provider-engine": "^7.2.1", "xtend": "^4.0.1" }, "devDependencies": {