From c89f156352466f5597a2da84c1815930ae856310 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 23 Jun 2020 17:31:30 +0200 Subject: [PATCH] provider as plugin --- apps/remix-ide/src/app/tabs/network-module.js | 9 +++-- .../remix-ide/src/app/tabs/runTab/settings.js | 14 ++++---- apps/remix-ide/src/app/udapp/run-tab.js | 22 +++++++++++++ apps/remix-ide/src/blockchain/blockchain.js | 9 ++--- apps/remix-ide/src/remixAppManager.js | 15 +++++++-- .../src/execution/execution-context.js | 33 +++++++++++-------- libs/remix-lib/src/execution/txRunner.js | 5 +++ workspace.json | 2 +- 8 files changed, 80 insertions(+), 29 deletions(-) diff --git a/apps/remix-ide/src/app/tabs/network-module.js b/apps/remix-ide/src/app/tabs/network-module.js index cb3e465044..58668123ff 100644 --- a/apps/remix-ide/src/app/tabs/network-module.js +++ b/apps/remix-ide/src/app/tabs/network-module.js @@ -1,5 +1,6 @@ import { Plugin } from '@remixproject/engine' import * as packageJson from '../../../../../package.json' +import { Web3 } from 'web3' export const profile = { name: 'network', @@ -59,8 +60,12 @@ export class NetworkModule extends Plugin { } /** Add a custom network to the list of available networks */ - addNetwork (customNetwork) { - this.blockchain.addProvider(customNetwork) + addNetwork (network) { // { name, url } + if (network.url === 'ipc') { + this.blockchain.addProvider({ name: network.name, provider: new Web3.providers.IpcProvider() }) + } else { + this.blockchain.addProvider({ name: network.name, provider: new Web3.providers.HttpProvider(network.url) }) + } } /** Remove a network to the list of availble networks */ diff --git a/apps/remix-ide/src/app/tabs/runTab/settings.js b/apps/remix-ide/src/app/tabs/runTab/settings.js index 692828e25e..e22a3c0064 100644 --- a/apps/remix-ide/src/app/tabs/runTab/settings.js +++ b/apps/remix-ide/src/app/tabs/runTab/settings.js @@ -156,7 +156,7 @@ class SettingsUI { setDropdown (selectExEnv) { this.selectExEnv = selectExEnv - this.blockchain.event.register('addProvider', (network) => { + const addProvider = (network) => { selectExEnv.appendChild(yo``) - addTooltip(`${network.name} [${network.url}] added`) - }) + addTooltip(yo`${network.name} provider added ${network.url ? `- ${network.url}` : ''}`) + } - this.blockchain.event.register('removeProvider', (name) => { + const removeProvider = (name) => { var env = selectExEnv.querySelector(`option[value="${name}"]`) if (env) { selectExEnv.removeChild(env) - addTooltip(`${name} removed`) + addTooltip(yo`${name} provider removed`) } - }) + } + this.blockchain.event.register('addProvider', provider => addProvider(provider)) + this.blockchain.event.register('removeProvider', name => removeProvider(name)) selectExEnv.addEventListener('change', (event) => { let context = selectExEnv.options[selectExEnv.selectedIndex].value diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js index 4c1978bf87..e6a40b5f15 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.js +++ b/apps/remix-ide/src/app/udapp/run-tab.js @@ -201,6 +201,28 @@ export class RunTab extends LibraryPlugin { this.renderDropdown(this.udappUI, this.fileManager, this.compilersArtefacts, this.config, this.editor, this.logCallback) this.renderRecorder(this.udappUI, this.fileManager, this.config, this.logCallback) this.renderRecorderCard() + + this.on('manager', 'pluginDeactivated', profile => { + if (profile.kind === 'provider') this.blockchain.removeProvider(profile.name) + }) + this.on('manager', 'pluginActivated', profile => { + if (profile.kind === 'provider') { + ((profile, app) => { + const web3Provider = { + sendAsync (payload, callback) { + app.call(profile.name, 'sendAsync', payload) + .then(result => { + callback(null, result) + }) + .catch(e => { + callback(e) + }) + } + } + this.blockchain.addProvider({ name: profile.displayName, provider: web3Provider }) + })(profile, this) + } + }) return this.renderContainer() } } diff --git a/apps/remix-ide/src/blockchain/blockchain.js b/apps/remix-ide/src/blockchain/blockchain.js index 5cace4f97d..cf57531072 100644 --- a/apps/remix-ide/src/blockchain/blockchain.js +++ b/apps/remix-ide/src/blockchain/blockchain.js @@ -67,7 +67,8 @@ class Blockchain { getCurrentProvider () { const provider = this.getProvider() - return this.providers[provider] + if (this.providers[provider]) return this.providers[provider] + return this.providers.web3 // default to the common type of provider } /** Return the list of accounts */ @@ -285,11 +286,11 @@ class Blockchain { this.resetEnvironment() } - addNetwork (customNetwork) { - this.executionContext.addProvider(customNetwork) + addProvider (provider) { + this.executionContext.addProvider(provider) } - removeNetwork (name) { + removeProvider (name) { this.executionContext.removeProvider(name) } diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index e866bc2641..bd14021538 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -20,7 +20,7 @@ export function canActivate (name) { export class RemixAppManager extends PluginManager { - constructor (plugins) { + constructor () { super() this.event = new EventEmitter() this.pluginsDirectory = 'https://raw.githubusercontent.com/ethereum/remix-plugins-directory/master/build/metadata.json' @@ -94,7 +94,18 @@ export class RemixAppManager extends PluginManager { async registeredPlugins () { const res = await fetch(this.pluginsDirectory) - const plugins = await res.json() + let plugins = await res.json() + plugins.push({ + 'name': 'walletconnect', + 'kind': 'provider', + 'displayName': 'Wallet Connect', + 'events': [], + 'methods': ['sendAsync'], + 'url': 'ipfs://QmWYfY6CGyU29LFw4QVSpwzfHxGh5kg4Tc5QNMA8ZYoHks', + 'description': 'Use your mobile wallet for transaction', + 'icon': 'data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHdpZHRoPSI1MTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxyYWRpYWxHcmFkaWVudCBpZD0iYSIgY3g9IjAlIiBjeT0iNTAlIiByPSIxMDAlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiM1ZDlkZjYiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMDZmZmYiLz48L3JhZGlhbEdyYWRpZW50PjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PHBhdGggZD0ibTI1NiAwYzE0MS4zODQ4OTYgMCAyNTYgMTE0LjYxNTEwNCAyNTYgMjU2cy0xMTQuNjE1MTA0IDI1Ni0yNTYgMjU2LTI1Ni0xMTQuNjE1MTA0LTI1Ni0yNTYgMTE0LjYxNTEwNC0yNTYgMjU2LTI1NnoiIGZpbGw9InVybCgjYSkiLz48cGF0aCBkPSJtNjQuNjkxNzU1OCAzNy43MDg4Mjk4YzUxLjUzMjgwNzItNTAuMjc4NDM5NyAxMzUuMDgzOTk0Mi01MC4yNzg0Mzk3IDE4Ni42MTY3OTkyIDBsNi4yMDIwNTcgNi4wNTEwOTA2YzIuNTc2NjQgMi41MTM5MjE4IDIuNTc2NjQgNi41ODk3OTQ4IDAgOS4xMDM3MTc3bC0yMS4yMTU5OTggMjAuNjk5NTc1OWMtMS4yODgzMjEgMS4yNTY5NjE5LTMuMzc3MSAxLjI1Njk2MTktNC42NjU0MjEgMGwtOC41MzQ3NjYtOC4zMjcwMjA1Yy0zNS45NTA1NzMtMzUuMDc1NDk2Mi05NC4yMzc5NjktMzUuMDc1NDk2Mi0xMzAuMTg4NTQ0IDBsLTkuMTQwMDI4MiA4LjkxNzU1MTljLTEuMjg4MzIxNyAxLjI1Njk2MDktMy4zNzcxMDE2IDEuMjU2OTYwOS00LjY2NTQyMDggMGwtMjEuMjE1OTk3My0yMC42OTk1NzU5Yy0yLjU3NjY0MDMtMi41MTM5MjI5LTIuNTc2NjQwMy02LjU4OTc5NTggMC05LjEwMzcxNzd6bTIzMC40OTM0ODUyIDQyLjgwODkxMTcgMTguODgyMjc5IDE4LjQyMjcyNjJjMi41NzY2MjcgMi41MTM5MTAzIDIuNTc2NjQyIDYuNTg5NzU5My4wMDAwMzIgOS4xMDM2ODYzbC04NS4xNDE0OTggODMuMDcwMzU4Yy0yLjU3NjYyMyAyLjUxMzk0MS02Ljc1NDE4MiAyLjUxMzk2OS05LjMzMDg0LjAwMDA2Ni0uMDAwMDEtLjAwMDAxLS4wMDAwMjMtLjAwMDAyMy0uMDAwMDMzLS4wMDAwMzRsLTYwLjQyODI1Ni01OC45NTc0NTFjLS42NDQxNi0uNjI4NDgxLTEuNjg4NTUtLjYyODQ4MS0yLjMzMjcxIDAtLjAwMDAwNC4wMDAwMDQtLjAwMDAwOC4wMDAwMDctLjAwMDAxMi4wMDAwMTFsLTYwLjQyNjk2ODMgNTguOTU3NDA4Yy0yLjU3NjYxNDEgMi41MTM5NDctNi43NTQxNzQ2IDIuNTEzOTktOS4zMzA4NDA4LjAwMDA5Mi0uMDAwMDE1MS0uMDAwMDE0LS4wMDAwMzA5LS4wMDAwMjktLjAwMDA0NjctLjAwMDA0NmwtODUuMTQzODY3NzQtODMuMDcxNDYzYy0yLjU3NjYzOTI4LTIuNTEzOTIxLTIuNTc2NjM5MjgtNi41ODk3OTUgMC05LjEwMzcxNjNsMTguODgyMzEyNjQtMTguNDIyNjk1NWMyLjU3NjYzOTMtMi41MTM5MjIyIDYuNzU0MTk5My0yLjUxMzkyMjIgOS4zMzA4Mzk3IDBsNjAuNDI5MTM0NyA1OC45NTgyNzU4Yy42NDQxNjA4LjYyODQ4IDEuNjg4NTQ5NS42Mjg0OCAyLjMzMjcxMDMgMCAuMDAwMDA5NS0uMDAwMDA5LjAwMDAxODItLjAwMDAxOC4wMDAwMjc3LS4wMDAwMjVsNjAuNDI2MTA2NS01OC45NTgyNTA4YzIuNTc2NTgxLTIuNTEzOTggNi43NTQxNDItMi41MTQwNzQzIDkuMzMwODQtLjAwMDIxMDMuMDAwMDM3LjAwMDAzNTQuMDAwMDcyLjAwMDA3MDkuMDAwMTA3LjAwMDEwNjNsNjAuNDI5MDU2IDU4Ljk1ODM1NDhjLjY0NDE1OS42Mjg0NzkgMS42ODg1NDkuNjI4NDc5IDIuMzMyNzA5IDBsNjAuNDI4MDc5LTU4Ljk1NzE5MjVjMi41NzY2NC0yLjUxMzkyMzEgNi43NTQxOTktMi41MTM5MjMxIDkuMzMwODM5IDB6IiBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHRyYW5zZm9ybT0idHJhbnNsYXRlKDk4IDE2MCkiLz48L2c+PC9zdmc+', + 'location': 'mainPanel' + }) return plugins.map(plugin => new IframePlugin(plugin)) } } diff --git a/libs/remix-lib/src/execution/execution-context.js b/libs/remix-lib/src/execution/execution-context.js index f1875a209a..1170cd174d 100644 --- a/libs/remix-lib/src/execution/execution-context.js +++ b/libs/remix-lib/src/execution/execution-context.js @@ -110,6 +110,7 @@ function ExecutionContext () { let executionContext = null + this.currentProviderName = null this.blockGasLimitDefault = 4300000 this.blockGasLimit = this.blockGasLimitDefault this.customNetWorks = {} @@ -174,13 +175,14 @@ function ExecutionContext () { this.removeProvider = (name) => { if (name && this.customNetWorks[name]) { + if (this.currentProviderName === name) this.setContext('vm', null) delete this.customNetWorks[name] this.event.trigger('removeProvider', [name]) } } this.addProvider = (network) => { - if (network && network.name && network.url) { + if (network && network.name && !this.customNetWorks[network.name]) { this.customNetWorks[network.name] = network this.event.trigger('addProvider', [network]) } @@ -205,9 +207,11 @@ function ExecutionContext () { this.executionContextChange = (context, endPointUrl, confirmCb, infoCb, cb) => { if (!cb) cb = () => {} - + if (!confirmCb) confirmCb = () => {} + if (!infoCb) infoCb = () => {} if (context === 'vm') { executionContext = context + this.currentProviderName = context vms[currentFork].stateManager.revert(() => { vms[currentFork].stateManager.checkpoint(() => {}) }) @@ -222,6 +226,7 @@ function ExecutionContext () { } else { this.askPermission() executionContext = context + this.currentProviderName = context web3.setProvider(injectedProvider) this._updateBlockGasLimit() this.event.trigger('contextChanged', ['injected']) @@ -234,8 +239,11 @@ function ExecutionContext () { } if (this.customNetWorks[context]) { - var provider = this.customNetWorks[context] - setProviderFromEndpoint(provider.url, 'web3', () => { cb() }) + var network = this.customNetWorks[context] + this.setProviderFromEndpoint(network.provider, network.name, (error) => { + if (error) infoCb(error) + cb() + }) } } @@ -269,29 +277,26 @@ function ExecutionContext () { // TODO: remove this when this function is moved const self = this - // TODO: not used here anymore and needs to be moved - function setProviderFromEndpoint (endpoint, context, cb) { + + this.setProviderFromEndpoint = (endpoint, context, cb) => { const oldProvider = web3.currentProvider - if (endpoint === 'ipc') { - web3.setProvider(new web3.providers.IpcProvider()) - } else { - web3.setProvider(new web3.providers.HttpProvider(endpoint)) - } + web3.setProvider(endpoint) + web3.eth.net.isListening((err, isConnected) => { if (!err && isConnected) { executionContext = context + this.currentProviderName = context self._updateBlockGasLimit() - self.event.trigger('contextChanged', ['web3']) + self.event.trigger('contextChanged', [context]) self.event.trigger('web3EndpointChanged') cb() } else { web3.setProvider(oldProvider) - cb('Not possible to connect to the Web3 provider. Make sure the provider is running and a connection is open (via IPC or RPC).') + cb('Not possible to connect to the Web3 provider. Make sure the provider is running, a connection is open (via IPC or RPC) or that the provider plugin is properly configured.') } }) } - this.setProviderFromEndpoint = setProviderFromEndpoint this.txDetailsLink = (network, hash) => { if (transactionDetailsLinks[network]) { diff --git a/libs/remix-lib/src/execution/txRunner.js b/libs/remix-lib/src/execution/txRunner.js index f778ceb388..32c625d94d 100644 --- a/libs/remix-lib/src/execution/txRunner.js +++ b/libs/remix-lib/src/execution/txRunner.js @@ -177,6 +177,11 @@ class TxRunner { }) } this.executionContext.web3().eth.estimateGas(tx, (err, gasEstimation) => { + console.log(err, gasEstimation) + if (err && err.message.indexOf('Invalid JSON RPC response') !== -1) { + // https://github.com/WalletConnect/walletconnect-monorepo/issues/334 + err = 'Gas estimation failed because of an unknown internal error. This may indicated that the transaction will fail.' + } gasEstimationForceSend(err, () => { // callback is called whenever no error tx.gas = !gasEstimation ? gasLimit : gasEstimation diff --git a/workspace.json b/workspace.json index d81084a528..686fb9b3eb 100644 --- a/workspace.json +++ b/workspace.json @@ -23,7 +23,7 @@ "styles": [], "scripts": [], "webpackConfig": "apps/remix-ide/webpack.config.js", - "maxWorkers": 2 + "maxWorkers": 1 }, "configurations": { "production": {