From d7619601f64d599996e7fd24dc407b9f1e72b1be Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 8 Feb 2023 13:01:02 +0100 Subject: [PATCH] add basicInjectedProvider --- apps/remix-ide/src/app.js | 7 ++- .../src/app/tabs/basic-injected-provider.tsx | 18 ++++++ .../src/app/tabs/external-http-provider.tsx | 2 +- .../src/app/tabs/foundry-provider.tsx | 2 +- .../src/app/tabs/ganache-provider.tsx | 6 +- .../src/app/tabs/hardhat-provider.tsx | 6 +- .../src/app/tabs/injected-L2-provider.tsx | 54 ++++++++++++++++ .../tabs/injected-arbitrum-one-provider.tsx | 11 ++-- .../app/tabs/injected-optimism-provider.tsx | 11 ++-- .../src/app/tabs/injected-provider.tsx | 61 +++++++------------ apps/remix-ide/src/app/udapp/run-tab.js | 6 ++ .../src/blockchain/execution-context.js | 51 +--------------- apps/remix-ide/src/remixAppManager.js | 4 +- .../run-tab/src/lib/reducers/runTab.ts | 9 --- 14 files changed, 122 insertions(+), 126 deletions(-) create mode 100644 apps/remix-ide/src/app/tabs/basic-injected-provider.tsx create mode 100644 apps/remix-ide/src/app/tabs/injected-L2-provider.tsx diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 322e1c4b23..5254e7a960 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -31,6 +31,7 @@ import { HardhatProvider } from './app/tabs/hardhat-provider' import { GanacheProvider } from './app/tabs/ganache-provider' import { FoundryProvider } from './app/tabs/foundry-provider' import { ExternalHttpProvider } from './app/tabs/external-http-provider' +import { BasicInjectedProvider } from './app/tabs/basic-injected-provider' import { Injected0ptimismProvider } from './app/tabs/injected-optimism-provider' import { InjectedArbitrumOneProvider } from './app/tabs/injected-arbitrum-one-provider' import { FileDecorator } from './app/plugins/file-decorator' @@ -205,8 +206,9 @@ class AppComponent { const ganacheProvider = new GanacheProvider(blockchain) const foundryProvider = new FoundryProvider(blockchain) const externalHttpProvider = new ExternalHttpProvider(blockchain) - const injected0ptimismProvider = new Injected0ptimismProvider(blockchain) - const injectedArbitrumOneProvider = new InjectedArbitrumOneProvider(blockchain) + const basicInjectedProvider = new BasicInjectedProvider() + const injected0ptimismProvider = new Injected0ptimismProvider() + const injectedArbitrumOneProvider = new InjectedArbitrumOneProvider() // ----------------- convert offset to line/column service ----------- const offsetToLineColumnConverter = new OffsetToLineColumnConverter() Registry.getInstance().put({ @@ -270,6 +272,7 @@ class AppComponent { ganacheProvider, foundryProvider, externalHttpProvider, + basicInjectedProvider, injected0ptimismProvider, injectedArbitrumOneProvider, this.walkthroughService, diff --git a/apps/remix-ide/src/app/tabs/basic-injected-provider.tsx b/apps/remix-ide/src/app/tabs/basic-injected-provider.tsx new file mode 100644 index 0000000000..95895a9dca --- /dev/null +++ b/apps/remix-ide/src/app/tabs/basic-injected-provider.tsx @@ -0,0 +1,18 @@ +import * as packageJson from '../../../../../package.json' +import { InjectedProvider } from './injected-provider' + +const profile = { + name: 'injected', + displayName: 'Injected Provider', + kind: 'provider', + description: 'injected Provider', + methods: ['sendAsync', 'init'], + version: packageJson.version +} + +export class BasicInjectedProvider extends InjectedProvider { + + constructor () { + super(profile) + } +} \ No newline at end of file diff --git a/apps/remix-ide/src/app/tabs/external-http-provider.tsx b/apps/remix-ide/src/app/tabs/external-http-provider.tsx index 9483989843..36d864c2a1 100644 --- a/apps/remix-ide/src/app/tabs/external-http-provider.tsx +++ b/apps/remix-ide/src/app/tabs/external-http-provider.tsx @@ -7,7 +7,7 @@ const profile = { displayName: 'External Http Provider', kind: 'provider', description: 'External Http Provider', - methods: ['sendAsync'], + methods: ['sendAsync', 'init'], version: packageJson.version } diff --git a/apps/remix-ide/src/app/tabs/foundry-provider.tsx b/apps/remix-ide/src/app/tabs/foundry-provider.tsx index 4d1df70715..904c330b3c 100644 --- a/apps/remix-ide/src/app/tabs/foundry-provider.tsx +++ b/apps/remix-ide/src/app/tabs/foundry-provider.tsx @@ -7,7 +7,7 @@ const profile = { displayName: 'Foundry Provider', kind: 'provider', description: 'Foundry Anvil provider', - methods: ['sendAsync'], + methods: ['sendAsync', 'init'], version: packageJson.version } diff --git a/apps/remix-ide/src/app/tabs/ganache-provider.tsx b/apps/remix-ide/src/app/tabs/ganache-provider.tsx index 597f2b4015..132aa20957 100644 --- a/apps/remix-ide/src/app/tabs/ganache-provider.tsx +++ b/apps/remix-ide/src/app/tabs/ganache-provider.tsx @@ -1,9 +1,5 @@ import * as packageJson from '../../../../../package.json' -import { Plugin } from '@remixproject/engine' -import { AppModal, AlertModal, ModalTypes } from '@remix-ui/app' import React from 'react' // eslint-disable-line -import { Blockchain } from '../../blockchain/blockchain' -import { ethers } from 'ethers' import { AbstractProvider } from './abstract-provider' const profile = { @@ -11,7 +7,7 @@ const profile = { displayName: 'Ganache Provider', kind: 'provider', description: 'Truffle Ganache provider', - methods: ['sendAsync'], + methods: ['sendAsync', 'init'], version: packageJson.version } diff --git a/apps/remix-ide/src/app/tabs/hardhat-provider.tsx b/apps/remix-ide/src/app/tabs/hardhat-provider.tsx index bc4c20e768..1d579ab6c1 100644 --- a/apps/remix-ide/src/app/tabs/hardhat-provider.tsx +++ b/apps/remix-ide/src/app/tabs/hardhat-provider.tsx @@ -1,9 +1,5 @@ import * as packageJson from '../../../../../package.json' -import { Plugin } from '@remixproject/engine' -import { AppModal, AlertModal, ModalTypes } from '@remix-ui/app' import React from 'react' // eslint-disable-line -import { Blockchain } from '../../blockchain/blockchain' -import { ethers } from 'ethers' import { AbstractProvider } from './abstract-provider' const profile = { @@ -11,7 +7,7 @@ const profile = { displayName: 'Hardhat Provider', kind: 'provider', description: 'Hardhat provider', - methods: ['sendAsync'], + methods: ['sendAsync', 'init'], version: packageJson.version } diff --git a/apps/remix-ide/src/app/tabs/injected-L2-provider.tsx b/apps/remix-ide/src/app/tabs/injected-L2-provider.tsx new file mode 100644 index 0000000000..18c761b47b --- /dev/null +++ b/apps/remix-ide/src/app/tabs/injected-L2-provider.tsx @@ -0,0 +1,54 @@ +import { InjectedProvider } from './injected-provider' + +export class InjectedL2Provider extends InjectedProvider { + chainName: string + chainId: string + rpcUrls: Array + + constructor (profile: any, chainName: string, chainId: string, rpcUrls: Array) { + super(profile) + this.chainName = chainName + this.chainId = chainId + this.rpcUrls = rpcUrls + } + + async init () { + await super.init() + if (this.chainName && this.rpcUrls && this.rpcUrls.length > 0) await addL2Network(this.chainName, this.chainId, this.rpcUrls) + else + throw new Error('Cannot add the L2 network to main injected provider') + } +} + +export const addL2Network = async (chainName: string, chainId: string, rpcUrls: Array) => { + try { + await (window as any).ethereum.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: chainId }], + }); + } catch (switchError) { + // This error code indicates that the chain has not been added to MetaMask. + if (switchError.code === 4902) { + try { + await (window as any).ethereum.request({ + method: 'wallet_addEthereumChain', + params: [ + { + chainId: chainId, + chainName: chainName, + rpcUrls: rpcUrls, + }, + ], + }); + + await (window as any).ethereum.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: chainId }], + }); + } catch (addError) { + // handle "add" error + } + } + // handle other "switch" errors + } +} \ No newline at end of file diff --git a/apps/remix-ide/src/app/tabs/injected-arbitrum-one-provider.tsx b/apps/remix-ide/src/app/tabs/injected-arbitrum-one-provider.tsx index 283dacdf24..aaf20e9070 100644 --- a/apps/remix-ide/src/app/tabs/injected-arbitrum-one-provider.tsx +++ b/apps/remix-ide/src/app/tabs/injected-arbitrum-one-provider.tsx @@ -1,21 +1,18 @@ import * as packageJson from '../../../../../package.json' -import { InjectedProvider } from './injected-provider' +import { InjectedL2Provider } from './injected-L2-provider' const profile = { name: 'injected-arbitrum-one-provider', displayName: 'Injected Arbitrum One Provider', kind: 'provider', description: 'injected Arbitrum One Provider', - methods: ['sendAsync'], + methods: ['sendAsync', 'init'], version: packageJson.version } -export class InjectedArbitrumOneProvider extends InjectedProvider { +export class InjectedArbitrumOneProvider extends InjectedL2Provider { constructor () { - super(profile) - this.chainName = 'Arbitrum One' - this.chainId = '0xa4b1' - this.rpcUrls = ['https://arb1.arbitrum.io/rpc'] + super(profile, 'Arbitrum One', '0xa4b1', ['https://arb1.arbitrum.io/rpc']) } } \ No newline at end of file diff --git a/apps/remix-ide/src/app/tabs/injected-optimism-provider.tsx b/apps/remix-ide/src/app/tabs/injected-optimism-provider.tsx index 64c8c4e91a..60037f415b 100644 --- a/apps/remix-ide/src/app/tabs/injected-optimism-provider.tsx +++ b/apps/remix-ide/src/app/tabs/injected-optimism-provider.tsx @@ -1,21 +1,18 @@ import * as packageJson from '../../../../../package.json' -import { InjectedProvider } from './injected-provider' +import { InjectedL2Provider } from './injected-L2-provider' const profile = { name: 'injected-optimism-provider', displayName: 'Injected Optimism Provider', kind: 'provider', description: 'injected Optimism Provider', - methods: ['sendAsync'], + methods: ['sendAsync', 'init'], version: packageJson.version } -export class Injected0ptimismProvider extends InjectedProvider { +export class Injected0ptimismProvider extends InjectedL2Provider { constructor () { - super(profile) - this.chainName = 'Optimism' - this.chainId = '0xa' - this.rpcUrls = ['https://mainnet.optimism.io'] + super(profile, 'Optimism', '0xa', ['https://mainnet.optimism.io']) } } \ No newline at end of file diff --git a/apps/remix-ide/src/app/tabs/injected-provider.tsx b/apps/remix-ide/src/app/tabs/injected-provider.tsx index 58defd1682..7d25fa27c4 100644 --- a/apps/remix-ide/src/app/tabs/injected-provider.tsx +++ b/apps/remix-ide/src/app/tabs/injected-provider.tsx @@ -1,13 +1,12 @@ +/* global ethereum */ import { Plugin } from '@remixproject/engine' import { JsonDataRequest, RejectRequest, SuccessRequest } from './abstract-provider' -import { ethers } from 'ethers' import Web3 from 'web3' +const noInjectedProviderMsg = 'No injected provider found. Make sure your provider (e.g. MetaMask) is active and running (when recently activated you may have to reload the page).' + export class InjectedProvider extends Plugin { provider: any - chainName: string - chainId: string - rpcUrls: Array constructor (profile) { super(profile) @@ -16,6 +15,26 @@ export class InjectedProvider extends Plugin { } } + askPermission (throwIfNoInjectedProvider) { + if (typeof (window as any).ethereum !== "undefined" && typeof (window as any).request === "function") { + (window as any).request({ method: "eth_requestAccounts" }) + } else if (throwIfNoInjectedProvider) { + throw new Error(noInjectedProviderMsg) + } + } + + async init () { + const injectedProvider = (window as any).ethereum + if (injectedProvider === undefined) { + throw new Error(noInjectedProviderMsg) + } else { + if (injectedProvider && injectedProvider._metamask && injectedProvider._metamask.isUnlocked) { + if (!await injectedProvider._metamask.isUnlocked()) throw new Error('Please make sure the injected provider is unlocked (e.g Metamask).') + } + this.askPermission(true) + } + } + sendAsync (data: JsonDataRequest): Promise { return new Promise((resolve, reject) => { this.sendAsyncInternal(data, resolve, reject) @@ -32,7 +51,6 @@ export class InjectedProvider extends Plugin { try { if ((window as any) && typeof (window as any).ethereum.request === "function") (window as any).ethereum.request({ method: "eth_requestAccounts" }); if (!await (window as any).ethereum._metamask.isUnlocked()) this.call('notification', 'toast', 'Please make sure the injected provider is unlocked (e.g Metamask).') - await addL2Network(this.chainName, this.chainId, this.rpcUrls) const resultData = await this.provider.currentProvider.send(data.method, data.params) resolve({ jsonrpc: '2.0', result: resultData.result, id: data.id }) } catch (error) { @@ -40,36 +58,3 @@ export class InjectedProvider extends Plugin { } } } - -export const addL2Network = async (chainName: string, chainId: string, rpcUrls: Array) => { - try { - await (window as any).ethereum.request({ - method: 'wallet_switchEthereumChain', - params: [{ chainId: chainId }], - }); - } catch (switchError) { - // This error code indicates that the chain has not been added to MetaMask. - if (switchError.code === 4902) { - try { - await (window as any).ethereum.request({ - method: 'wallet_addEthereumChain', - params: [ - { - chainId: chainId, - chainName: chainName, - rpcUrls: rpcUrls, - }, - ], - }); - - await (window as any).ethereum.request({ - method: 'wallet_switchEthereumChain', - params: [{ chainId: chainId }], - }); - } catch (addError) { - // handle "add" error - } - } - // handle other "switch" errors - } -} diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js index 39c2cadeea..c6712543f4 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.js +++ b/apps/remix-ide/src/app/udapp/run-tab.js @@ -124,6 +124,12 @@ export class RunTab extends ViewPlugin { await addProvider('foundry-provider', 'Foundry Provider', false) await addProvider('walletconnect', 'Wallet Connect', false) await addProvider('basic-http-provider', 'External Http Provider', false) + + const displayNameInjected = `Injected Provider${(window && window.ethereum && !(window.ethereum.providers && !window.ethereum.selectedProvider)) ? + window.ethereum.isCoinbaseWallet || window.ethereum.selectedProvider?.isCoinbaseWallet ? ' - Coinbase' : + window.ethereum.isBraveWallet || window.ethereum.selectedProvider?.isBraveWallet ? ' - Brave' : + window.ethereum.isMetaMask || window.ethereum.selectedProvider?.isMetaMask ? ' - MetaMask' : '' : ''}` + await addProvider('injected', displayNameInjected, true) await addProvider('injected-optimism-provider', 'Optimism Provider', true) await addProvider('injected-arbitrum-one-provider', 'Arbitrum One Provider', true) } diff --git a/apps/remix-ide/src/blockchain/execution-context.js b/apps/remix-ide/src/blockchain/execution-context.js index bdd403b93c..e7264d2968 100644 --- a/apps/remix-ide/src/blockchain/execution-context.js +++ b/apps/remix-ide/src/blockchain/execution-context.js @@ -14,8 +14,6 @@ if (typeof window !== 'undefined' && typeof window.ethereum !== 'undefined') { web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')) } -const noInjectedProviderMsg = 'No injected provider found. Make sure your provider (e.g. MetaMask) is active and running (when recently activated you may have to reload the page).' - /* trigger contextChanged, web3EndpointChanged */ @@ -38,19 +36,8 @@ export class ExecutionContext { init (config) { if (config.get('settings/always-use-vm')) { this.executionContext = 'vm' - } else { - this.executionContext = injectedProvider ? 'injected' : 'vm' - if (this.executionContext === 'injected') this.askPermission(false) - } - } - - askPermission (throwIfNoInjectedProvider) { - if (typeof ethereum !== "undefined" && typeof ethereum.request === "function") { - ethereum.request({ method: "eth_requestAccounts" }) - } else if (throwIfNoInjectedProvider) { - throw new Error(noInjectedProviderMsg) } - } + } getProvider () { return this.executionContext @@ -84,12 +71,6 @@ export class ExecutionContext { if (!web3.currentProvider) { return callback('No provider set') } - if (web3.currentProvider.isConnected && !web3.currentProvider.isConnected()) { - if (web3.currentProvider.isMetaMask) { - this.askPermission(false) - } - return callback('Provider not connected') - } web3.eth.net.getId((err, id) => { let name = null if (err) name = 'Unknown' @@ -152,28 +133,6 @@ export class ExecutionContext { return cb() } - if (context === 'injected') { - if (injectedProvider === undefined) { - infoCb(noInjectedProviderMsg) - return cb() - } else { - if (injectedProvider && injectedProvider._metamask && injectedProvider._metamask.isUnlocked) { - if (!await injectedProvider._metamask.isUnlocked()) infoCb('Please make sure the injected provider is unlocked (e.g Metamask).') - } - try { - this.askPermission(true) - } catch (e) { - infoCb(e.message) - return cb() - } - this.executionContext = context - web3.setProvider(injectedProvider) - await this._updateChainContext() - this.event.trigger('contextChanged', ['injected']) - return cb() - } - } - if (this.customNetWorks[context]) { var network = this.customNetWorks[context] if (!this.customNetWorks[context].isInjected) { @@ -182,13 +141,7 @@ export class ExecutionContext { cb() }) } else { - // injected - try { - this.askPermission(true) - } catch (e) { - infoCb(e.message) - return cb() - } + // injected this.executionContext = context web3.setProvider(network.provider) await this._updateChainContext() diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 91c221588a..2ca45b728f 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -10,7 +10,7 @@ const requiredModules = [ // services + layout views + system views 'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout', 'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy', - 'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected-optimism-provider', 'injected-arbitrum-one-provider', + 'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected', 'injected-optimism-provider', 'injected-arbitrum-one-provider', 'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser', 'codeFormatter', 'solidityumlgen', 'contractflattener'] // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) @@ -26,7 +26,7 @@ export function isNative(name) { // nativePlugin allows to bypass the permission request const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'solidity-logic', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'notification', 'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected-optimism-provider', - 'tabs', 'injected-arbitrum-one-provider'] + 'tabs', 'injected-arbitrum-one-provider', 'injected'] return nativePlugins.includes(name) || requiredModules.includes(name) } diff --git a/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts b/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts index 3ee59195be..69c3736f14 100644 --- a/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts +++ b/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts @@ -133,15 +133,6 @@ export const runTabInitialState: RunTabState = { value: 'vm-berlin', fork: 'berlin', content: 'Remix VM (Berlin)' - }, { - id: 'injected-mode', - dataId: 'settingsInjectedMode', - title: 'Execution environment has been provided by Metamask or similar provider.', - value: 'injected', - content: `Injected Provider${(window && window.ethereum && !(window.ethereum.providers && !window.ethereum.selectedProvider)) ? - window.ethereum.isCoinbaseWallet || window.ethereum.selectedProvider?.isCoinbaseWallet ? ' - Coinbase' : - window.ethereum.isBraveWallet || window.ethereum.selectedProvider?.isBraveWallet ? ' - Brave' : - window.ethereum.isMetaMask || window.ethereum.selectedProvider?.isMetaMask ? ' - MetaMask' : '' : ''}` }], isRequesting: false, isSuccessful: false,