From 03f543a9a45131e7eaeb5c4263289090afa1c7dc Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 23 Aug 2023 14:46:30 +0200 Subject: [PATCH] add ephemery provider --- apps/remix-ide/src/app.js | 240 ++++++++---------- .../injected-arbitrum-one-provider.tsx | 4 +- ...vider.tsx => injected-custom-provider.tsx} | 8 +- .../injected-ephemery-testnet-provider.tsx | 17 ++ .../providers/injected-optimism-provider.tsx | 4 +- apps/remix-ide/src/app/udapp/run-tab.js | 92 ++++--- apps/remix-ide/src/remixAppManager.js | 152 ++++++++--- 7 files changed, 311 insertions(+), 206 deletions(-) rename apps/remix-ide/src/app/providers/{injected-L2-provider.tsx => injected-custom-provider.tsx} (79%) create mode 100644 apps/remix-ide/src/app/providers/injected-ephemery-testnet-provider.tsx diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 9864bbd567..b06efcf956 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -1,57 +1,58 @@ 'use strict' -import { RunTab, makeUdapp } from './app/udapp' -import { RemixEngine } from './remixEngine' -import { RemixAppManager } from './remixAppManager' -import { ThemeModule } from './app/tabs/theme-module' -import { LocaleModule } from './app/tabs/locale-module' -import { NetworkModule } from './app/tabs/network-module' -import { Web3ProviderModule } from './app/tabs/web3-provider' -import { CompileAndRun } from './app/tabs/compile-and-run' -import { SidePanel } from './app/components/side-panel' -import { HiddenPanel } from './app/components/hidden-panel' -import { VerticalIcons } from './app/components/vertical-icons' -import { LandingPage } from './app/ui/landing-page/landing-page' -import { MainPanel } from './app/components/main-panel' -import { PermissionHandlerPlugin } from './app/plugins/permission-handler-plugin' -import { AstWalker } from '@remix-project/remix-astwalker' -import { LinkLibraries, DeployLibraries, OpenZeppelinProxy } from '@remix-project/core-plugin' -import { CodeParser } from './app/plugins/parser/code-parser' -import { SolidityScript } from './app/plugins/solidity-script' - -import { WalkthroughService } from './walkthroughService' - -import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports, GistHandler } from '@remix-project/core-plugin' +import {RunTab, makeUdapp} from './app/udapp' +import {RemixEngine} from './remixEngine' +import {RemixAppManager} from './remixAppManager' +import {ThemeModule} from './app/tabs/theme-module' +import {LocaleModule} from './app/tabs/locale-module' +import {NetworkModule} from './app/tabs/network-module' +import {Web3ProviderModule} from './app/tabs/web3-provider' +import {CompileAndRun} from './app/tabs/compile-and-run' +import {SidePanel} from './app/components/side-panel' +import {HiddenPanel} from './app/components/hidden-panel' +import {VerticalIcons} from './app/components/vertical-icons' +import {LandingPage} from './app/ui/landing-page/landing-page' +import {MainPanel} from './app/components/main-panel' +import {PermissionHandlerPlugin} from './app/plugins/permission-handler-plugin' +import {AstWalker} from '@remix-project/remix-astwalker' +import {LinkLibraries, DeployLibraries, OpenZeppelinProxy} from '@remix-project/core-plugin' +import {CodeParser} from './app/plugins/parser/code-parser' +import {SolidityScript} from './app/plugins/solidity-script' + +import {WalkthroughService} from './walkthroughService' + +import {OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports, GistHandler} from '@remix-project/core-plugin' import Registry from './app/state/registry' -import { ConfigPlugin } from './app/plugins/config' -import { StoragePlugin } from './app/plugins/storage' -import { Layout } from './app/panels/layout' -import { NotificationPlugin } from './app/plugins/notification' -import { Blockchain } from './blockchain/blockchain' -import { MergeVMProvider, LondonVMProvider, BerlinVMProvider, ShanghaiVMProvider } from './app/providers/vm-provider' -import { MainnetForkVMProvider } from './app/providers/mainnet-vm-fork-provider' -import { SepoliaForkVMProvider } from './app/providers/sepolia-vm-fork-provider' -import { GoerliForkVMProvider } from './app/providers/goerli-vm-fork-provider' -import { CustomForkVMProvider } from './app/providers/custom-vm-fork-provider' -import { HardhatProvider } from './app/providers/hardhat-provider' -import { GanacheProvider } from './app/providers/ganache-provider' -import { FoundryProvider } from './app/providers/foundry-provider' -import { ExternalHttpProvider } from './app/providers/external-http-provider' -import { InjectedProviderDefault } from './app/providers/injected-provider-default' -import { InjectedProviderTrustWallet } from './app/providers/injected-provider-trustwallet' -import { Injected0ptimismProvider } from './app/providers/injected-optimism-provider' -import { InjectedArbitrumOneProvider } from './app/providers/injected-arbitrum-one-provider' -import { FileDecorator } from './app/plugins/file-decorator' -import { CodeFormat } from './app/plugins/code-format' -import { SolidityUmlGen } from './app/plugins/solidity-umlgen' -import { ContractFlattener } from './app/plugins/contractFlattener' +import {ConfigPlugin} from './app/plugins/config' +import {StoragePlugin} from './app/plugins/storage' +import {Layout} from './app/panels/layout' +import {NotificationPlugin} from './app/plugins/notification' +import {Blockchain} from './blockchain/blockchain' +import {MergeVMProvider, LondonVMProvider, BerlinVMProvider, ShanghaiVMProvider} from './app/providers/vm-provider' +import {MainnetForkVMProvider} from './app/providers/mainnet-vm-fork-provider' +import {SepoliaForkVMProvider} from './app/providers/sepolia-vm-fork-provider' +import {GoerliForkVMProvider} from './app/providers/goerli-vm-fork-provider' +import {CustomForkVMProvider} from './app/providers/custom-vm-fork-provider' +import {HardhatProvider} from './app/providers/hardhat-provider' +import {GanacheProvider} from './app/providers/ganache-provider' +import {FoundryProvider} from './app/providers/foundry-provider' +import {ExternalHttpProvider} from './app/providers/external-http-provider' +import {InjectedProviderDefault} from './app/providers/injected-provider-default' +import {InjectedProviderTrustWallet} from './app/providers/injected-provider-trustwallet' +import {Injected0ptimismProvider} from './app/providers/injected-optimism-provider' +import {InjectedArbitrumOneProvider} from './app/providers/injected-arbitrum-one-provider' +import {InjectedEphemeryTestnetProvider} from './app/providers/injected-ephemery-testnet-provider' +import {FileDecorator} from './app/plugins/file-decorator' +import {CodeFormat} from './app/plugins/code-format' +import {SolidityUmlGen} from './app/plugins/solidity-umlgen' +import {ContractFlattener} from './app/plugins/contractFlattener' const isElectron = require('is-electron') const remixLib = require('@remix-project/remix-lib') -import { QueryParams } from '@remix-project/remix-lib' -import { SearchPlugin } from './app/tabs/search' +import {QueryParams} from '@remix-project/remix-lib' +import {SearchPlugin} from './app/tabs/search' const Storage = remixLib.Storage const RemixDProvider = require('./app/files/remixDProvider') @@ -67,12 +68,12 @@ const PluginManagerComponent = require('./app/components/plugin-manager-componen const CompileTab = require('./app/tabs/compile-tab') const SettingsTab = require('./app/tabs/settings-tab') const AnalysisTab = require('./app/tabs/analysis-tab') -const { DebuggerTab } = require('./app/tabs/debugger-tab') +const {DebuggerTab} = require('./app/tabs/debugger-tab') const TestTab = require('./app/tabs/test-tab') const FilePanel = require('./app/panels/file-panel') const Editor = require('./app/editor/editor') const Terminal = require('./app/panels/terminal') -const { TabProxy } = require('./app/panels/tab-proxy.js') +const {TabProxy} = require('./app/panels/tab-proxy.js') class AppComponent { constructor() { @@ -84,7 +85,7 @@ class AppComponent { // load app config const config = new Config(configStorage) - Registry.getInstance().put({ api: config, name: 'config' }) + Registry.getInstance().put({api: config, name: 'config'}) // load file system this._components.filesProviders = {} @@ -93,9 +94,7 @@ class AppComponent { api: this._components.filesProviders.browser, name: 'fileproviders/browser' }) - this._components.filesProviders.localhost = new RemixDProvider( - this.appManager - ) + this._components.filesProviders.localhost = new RemixDProvider(this.appManager) Registry.getInstance().put({ api: this._components.filesProviders.localhost, name: 'fileproviders/localhost' @@ -119,7 +118,7 @@ class AppComponent { this.panels = {} this.workspace = pluginLoader.get() this.engine = new RemixEngine() - this.engine.register(appManager); + this.engine.register(appManager) const matomoDomains = { 'remix-alpha.ethereum.org': 27, @@ -127,15 +126,8 @@ class AppComponent { 'remix.ethereum.org': 23, '6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod': 35 // remix desktop } - this.showMatamo = - matomoDomains[window.location.hostname] && - !Registry.getInstance() - .get('config') - .api.exists('settings/matomo-analytics') - this.walkthroughService = new WalkthroughService( - appManager, - this.showMatamo - ) + this.showMatamo = matomoDomains[window.location.hostname] && !Registry.getInstance().get('config').api.exists('settings/matomo-analytics') + this.walkthroughService = new WalkthroughService(appManager, this.showMatamo) const hosts = ['127.0.0.1:8080', '192.168.0.101:8080', 'localhost:8080'] // workaround for Electron support @@ -153,12 +145,12 @@ class AppComponent { this.themeModule = new ThemeModule() // ----------------- locale service --------------------------------- this.localeModule = new LocaleModule() - Registry.getInstance().put({ api: this.themeModule, name: 'themeModule' }) - Registry.getInstance().put({ api: this.localeModule, name: 'localeModule' }) + Registry.getInstance().put({api: this.themeModule, name: 'themeModule'}) + Registry.getInstance().put({api: this.localeModule, name: 'localeModule'}) // ----------------- editor service ---------------------------- const editor = new Editor() // wrapper around ace editor - Registry.getInstance().put({ api: editor, name: 'editor' }) + Registry.getInstance().put({api: editor, name: 'editor'}) editor.event.register('requiringToSaveCurrentfile', (currentFile) => { fileManager.saveCurrentFile() if (currentFile.endsWith('.circom')) this.appManager.activatePlugin(['circuit-compiler']) @@ -166,7 +158,7 @@ class AppComponent { // ----------------- fileManager service ---------------------------- const fileManager = new FileManager(editor, appManager) - Registry.getInstance().put({ api: fileManager, name: 'filemanager' }) + Registry.getInstance().put({api: fileManager, name: 'filemanager'}) // ----------------- dGit provider --------------------------------- const dGitProvider = new DGitProvider() @@ -221,9 +213,10 @@ class AppComponent { const foundryProvider = new FoundryProvider(blockchain) const externalHttpProvider = new ExternalHttpProvider(blockchain) const trustWalletInjectedProvider = new InjectedProviderTrustWallet() - const defaultInjectedProvider = new InjectedProviderDefault + const defaultInjectedProvider = new InjectedProviderDefault() const injected0ptimismProvider = new Injected0ptimismProvider() const injectedArbitrumOneProvider = new InjectedArbitrumOneProvider() + const injectedEphemeryTestnetProvider = new InjectedEphemeryTestnetProvider() // ----------------- convert offset to line/column service ----------- const offsetToLineColumnConverter = new OffsetToLineColumnConverter() Registry.getInstance().put({ @@ -233,11 +226,11 @@ class AppComponent { // ----------------- run script after each compilation results ----------- const compileAndRun = new CompileAndRun() // -------------------Terminal---------------------------------------- - makeUdapp(blockchain, compilersArtefacts, domEl => terminal.logHtml(domEl)) + makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl)) const terminal = new Terminal( - { appManager, blockchain }, + {appManager, blockchain}, { - getPosition: event => { + getPosition: (event) => { const limitUp = 36 const limitDown = 20 const height = window.innerHeight @@ -299,6 +292,7 @@ class AppComponent { trustWalletInjectedProvider, injected0ptimismProvider, injectedArbitrumOneProvider, + injectedEphemeryTestnetProvider, this.walkthroughService, search, solidityumlgen, @@ -308,7 +302,7 @@ class AppComponent { // LAYOUT & SYSTEM VIEWS const appPanel = new MainPanel() - Registry.getInstance().put({ api: this.mainview, name: 'mainview' }) + Registry.getInstance().put({api: this.mainview, name: 'mainview'}) const tabProxy = new TabProxy(fileManager, editor) this.engine.register([appPanel, tabProxy]) @@ -317,42 +311,18 @@ class AppComponent { this.sidePanel = new SidePanel() this.hiddenPanel = new HiddenPanel() - const pluginManagerComponent = new PluginManagerComponent( - appManager, - this.engine - ) + const pluginManagerComponent = new PluginManagerComponent(appManager, this.engine) const filePanel = new FilePanel(appManager) - const landingPage = new LandingPage( - appManager, - this.menuicons, - fileManager, - filePanel, - contentImport - ) - this.settings = new SettingsTab( - Registry.getInstance().get('config').api, - editor, - appManager - ) + const landingPage = new LandingPage(appManager, this.menuicons, fileManager, filePanel, contentImport) + this.settings = new SettingsTab(Registry.getInstance().get('config').api, editor, appManager) - this.engine.register([ - this.menuicons, - landingPage, - this.hiddenPanel, - this.sidePanel, - filePanel, - pluginManagerComponent, - this.settings - ]) + this.engine.register([this.menuicons, landingPage, this.hiddenPanel, this.sidePanel, filePanel, pluginManagerComponent, this.settings]) // CONTENT VIEWS & DEFAULT PLUGINS const openZeppelinProxy = new OpenZeppelinProxy(blockchain) const linkLibraries = new LinkLibraries(blockchain) const deployLibraries = new DeployLibraries(blockchain) - const compileTab = new CompileTab( - Registry.getInstance().get('config').api, - Registry.getInstance().get('filemanager').api - ) + const compileTab = new CompileTab(Registry.getInstance().get('config').api, Registry.getInstance().get('filemanager').api) const run = new RunTab( blockchain, Registry.getInstance().get('config').api, @@ -392,10 +362,10 @@ class AppComponent { ]) this.layout.panels = { - tabs: { plugin: tabProxy, active: true }, - editor: { plugin: editor, active: true }, - main: { plugin: appPanel, active: false }, - terminal: { plugin: terminal, active: true, minimized: false } + tabs: {plugin: tabProxy, active: true}, + editor: {plugin: editor, active: true}, + main: {plugin: appPanel, active: false}, + terminal: {plugin: terminal, active: true, minimized: false} } } @@ -411,27 +381,44 @@ class AppComponent { await this.appManager.activatePlugin(['layout']) await this.appManager.activatePlugin(['notification']) await this.appManager.activatePlugin(['editor']) - await this.appManager.activatePlugin(['permissionhandler', 'theme', 'locale', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter']) + await this.appManager.activatePlugin([ + 'permissionhandler', + 'theme', + 'locale', + 'fileManager', + 'compilerMetadata', + 'compilerArtefacts', + 'network', + 'web3Provider', + 'offsetToLineColumnConverter' + ]) await this.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs']) await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately await this.appManager.activatePlugin(['home']) await this.appManager.activatePlugin(['settings', 'config']) - await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'codeParser', 'codeFormatter', 'fileDecorator', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler']) + await this.appManager.activatePlugin([ + 'hiddenPanel', + 'pluginManager', + 'codeParser', + 'codeFormatter', + 'fileDecorator', + 'terminal', + 'blockchain', + 'fetchAndCompile', + 'contentImport', + 'gistHandler' + ]) await this.appManager.activatePlugin(['settings']) await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder']) await this.appManager.activatePlugin(['solidity-script']) - this.appManager.on( - 'filePanel', - 'workspaceInitializationCompleted', - async () => { - // for e2e tests - const loadedElement = document.createElement('span') - loadedElement.setAttribute('data-id', 'workspaceloaded') - document.body.appendChild(loadedElement) - await this.appManager.registerContextMenuItems() - } - ) + this.appManager.on('filePanel', 'workspaceInitializationCompleted', async () => { + // for e2e tests + const loadedElement = document.createElement('span') + loadedElement.setAttribute('data-id', 'workspaceloaded') + document.body.appendChild(loadedElement) + await this.appManager.registerContextMenuItems() + }) await this.appManager.activatePlugin(['filePanel']) // Set workspace after initial activation @@ -442,9 +429,7 @@ class AppComponent { .then(async () => { try { if (params.deactivate) { - await this.appManager.deactivatePlugin( - params.deactivate.split(',') - ) + await this.appManager.deactivatePlugin(params.deactivate.split(',')) } } catch (e) { console.log(e) @@ -454,10 +439,7 @@ class AppComponent { this.menuicons.select('solidity') } else { // If plugins are loaded from the URL params, we focus on the last one. - if ( - this.appManager.pluginLoader.current === 'queryParams' && - this.workspace.length > 0 - ) { + if (this.appManager.pluginLoader.current === 'queryParams' && this.workspace.length > 0) { this.menuicons.select(this.workspace[this.workspace.length - 1]) } else { this.appManager.call('tabs', 'focus', 'home') @@ -474,17 +456,13 @@ class AppComponent { } if (params.calls) { - const calls = params.calls.split("///"); + const calls = params.calls.split('///') // call all functions in the list, one after the other for (const call of calls) { - const callDetails = call.split("//"); + const callDetails = call.split('//') if (callDetails.length > 1) { - this.appManager.call( - "notification", - "toast", - `initiating ${callDetails[0]} and calling "${callDetails[1]}" ...` - ); + this.appManager.call('notification', 'toast', `initiating ${callDetails[0]} and calling "${callDetails[1]}" ...`) // @todo(remove the timeout when activatePlugin is on 0.3.0) try { diff --git a/apps/remix-ide/src/app/providers/injected-arbitrum-one-provider.tsx b/apps/remix-ide/src/app/providers/injected-arbitrum-one-provider.tsx index eb1ba39a7a..890f31aa9c 100644 --- a/apps/remix-ide/src/app/providers/injected-arbitrum-one-provider.tsx +++ b/apps/remix-ide/src/app/providers/injected-arbitrum-one-provider.tsx @@ -1,5 +1,5 @@ import * as packageJson from '../../../../../package.json' -import {InjectedL2Provider} from './injected-L2-provider' +import {InjectedCustomProvider} from './injected-custom-provider' const profile = { name: 'injected-arbitrum-one-provider', @@ -10,7 +10,7 @@ const profile = { version: packageJson.version } -export class InjectedArbitrumOneProvider extends InjectedL2Provider { +export class InjectedArbitrumOneProvider extends InjectedCustomProvider { constructor() { super(profile, 'Arbitrum One', '0xa4b1', ['https://arb1.arbitrum.io/rpc']) } diff --git a/apps/remix-ide/src/app/providers/injected-L2-provider.tsx b/apps/remix-ide/src/app/providers/injected-custom-provider.tsx similarity index 79% rename from apps/remix-ide/src/app/providers/injected-L2-provider.tsx rename to apps/remix-ide/src/app/providers/injected-custom-provider.tsx index 43cc43aa28..9e9807e78c 100644 --- a/apps/remix-ide/src/app/providers/injected-L2-provider.tsx +++ b/apps/remix-ide/src/app/providers/injected-custom-provider.tsx @@ -1,6 +1,6 @@ import {InjectedProviderDefaultBase} from './injected-provider-default' -export class InjectedL2Provider extends InjectedProviderDefaultBase { +export class InjectedCustomProvider extends InjectedProviderDefaultBase { chainName: string chainId: string rpcUrls: Array @@ -14,13 +14,13 @@ export class InjectedL2Provider extends InjectedProviderDefaultBase { 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') + if (this.chainName && this.rpcUrls && this.rpcUrls.length > 0) await addCustomNetwork(this.chainName, this.chainId, this.rpcUrls) + else throw new Error('Cannot add the custom network to main injected provider') return {} } } -export const addL2Network = async (chainName: string, chainId: string, rpcUrls: Array) => { +export const addCustomNetwork = async (chainName: string, chainId: string, rpcUrls: Array) => { try { await (window as any).ethereum.request({ method: 'wallet_switchEthereumChain', diff --git a/apps/remix-ide/src/app/providers/injected-ephemery-testnet-provider.tsx b/apps/remix-ide/src/app/providers/injected-ephemery-testnet-provider.tsx new file mode 100644 index 0000000000..9cfcb3f493 --- /dev/null +++ b/apps/remix-ide/src/app/providers/injected-ephemery-testnet-provider.tsx @@ -0,0 +1,17 @@ +import * as packageJson from '../../../../../package.json' +import {InjectedCustomProvider} from './injected-custom-provider' + +const profile = { + name: 'injected-ephemery-testnet-provider', + displayName: 'Injected Ephemery Testnet Provider', + kind: 'provider', + description: 'Injected Ephemery Testnet Provider', + methods: ['sendAsync', 'init'], + version: packageJson.version +} + +export class InjectedEphemeryTestnetProvider extends InjectedCustomProvider { + constructor() { + super(profile, 'Ephemery Testnet', '0x259C709', ['https://otter.bordel.wtf/erigon', 'https://eth.ephemeral.zeus.fyi']) + } +} diff --git a/apps/remix-ide/src/app/providers/injected-optimism-provider.tsx b/apps/remix-ide/src/app/providers/injected-optimism-provider.tsx index 9c8729dd84..592ae28b1a 100644 --- a/apps/remix-ide/src/app/providers/injected-optimism-provider.tsx +++ b/apps/remix-ide/src/app/providers/injected-optimism-provider.tsx @@ -1,5 +1,5 @@ import * as packageJson from '../../../../../package.json' -import {InjectedL2Provider} from './injected-L2-provider' +import {InjectedCustomProvider} from './injected-custom-provider' const profile = { name: 'injected-optimism-provider', @@ -10,7 +10,7 @@ const profile = { version: packageJson.version } -export class Injected0ptimismProvider extends InjectedL2Provider { +export class Injected0ptimismProvider extends InjectedCustomProvider { constructor() { super(profile, 'Optimism', '0xa', ['https://mainnet.optimism.io']) } diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js index ec389b1db8..9454fc57af 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.js +++ b/apps/remix-ide/src/app/udapp/run-tab.js @@ -1,12 +1,12 @@ import React from 'react' // eslint-disable-line -import { RunTabUI } from '@remix-ui/run-tab' -import { ViewPlugin } from '@remixproject/engine-web' -import { addressToString } from '@remix-ui/helper' +import {RunTabUI} from '@remix-ui/run-tab' +import {ViewPlugin} from '@remixproject/engine-web' +import {addressToString} from '@remix-ui/helper' import * as packageJson from '../../../../../package.json' const EventManager = require('../../lib/events') const Recorder = require('../tabs/runTab/model/recorder.js') -const _paq = window._paq = window._paq || [] +const _paq = (window._paq = window._paq || []) const profile = { name: 'udapp', @@ -20,11 +20,21 @@ const profile = { maintainedBy: 'Remix', permission: true, events: ['newTransaction'], - methods: ['createVMAccount', 'sendTransaction', 'getAccounts', 'pendingTransactionsCount', 'getSettings', 'setEnvironmentMode', 'clearAllInstances', 'addInstance', 'resolveContractAndAddInstance'] + methods: [ + 'createVMAccount', + 'sendTransaction', + 'getAccounts', + 'pendingTransactionsCount', + 'getSettings', + 'setEnvironmentMode', + 'clearAllInstances', + 'addInstance', + 'resolveContractAndAddInstance' + ] } export class RunTab extends ViewPlugin { - constructor (blockchain, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, fileProvider) { + constructor(blockchain, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, fileProvider) { super(profile) this.event = new EventManager() this.config = config @@ -41,13 +51,13 @@ export class RunTab extends ViewPlugin { this.el = document.createElement('div') } - setupEvents () { + setupEvents() { this.blockchain.events.on('newTransaction', (tx, receipt) => { this.emit('newTransaction', tx, receipt) }) } - getSettings () { + getSettings() { return new Promise((resolve, reject) => { resolve({ selectedAccount: this.REACT_API.accounts.selectedAccount, @@ -57,48 +67,52 @@ export class RunTab extends ViewPlugin { }) } - async setEnvironmentMode (env) { + async setEnvironmentMode(env) { const canCall = await this.askUserPermission('setEnvironmentMode', 'change the environment used') if (canCall) { - env = typeof env === 'string' ? { context: env } : env + env = typeof env === 'string' ? {context: env} : env this.emit('setEnvironmentModeReducer', env, this.currentRequest.from) } } - clearAllInstances () { + clearAllInstances() { this.emit('clearAllInstancesReducer') } - addInstance (address, abi, name) { + addInstance(address, abi, name) { this.emit('addInstanceReducer', address, abi, name) } - createVMAccount (newAccount) { + createVMAccount(newAccount) { return this.blockchain.createVMAccount(newAccount) } - sendTransaction (tx) { + sendTransaction(tx) { _paq.push(['trackEvent', 'udapp', 'sendTx', 'udappTransaction']) return this.blockchain.sendTransaction(tx) } - getAccounts (cb) { + getAccounts(cb) { return this.blockchain.getAccounts(cb) } - pendingTransactionsCount () { + pendingTransactionsCount() { return this.blockchain.pendingTransactionsCount() } - render () { - return
+ render() { + return ( +
+ +
+ ) } - onReady (api) { + onReady(api) { this.REACT_API = api } - async onInitDone () { + async onInitDone() { const udapp = this // eslint-disable-line const addProvider = async (name, displayName, isInjected, isVM, fork = '', dataId = '', title = '') => { @@ -113,13 +127,13 @@ export class RunTab extends ViewPlugin { title, init: async function () { const options = await udapp.call(name, 'init') - if (options) { + if (options) { this.options = options if (options['fork']) this.fork = options['fork'] } }, provider: { - async sendAsync (payload, callback) { + async sendAsync(payload, callback) { try { const result = await udapp.call(name, 'sendAsync', payload) callback(null, result) @@ -134,10 +148,17 @@ export class RunTab extends ViewPlugin { // basic injected // if it's the trust wallet provider, we have a specific provider for that, see below if (window && window.ethereum && !(window.ethereum.isTrustWallet || window.ethereum.selectedProvider?.isTrustWallet)) { - 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' : '' : ''}` + 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, false) } else if (window && !window.ethereum) { // we still add "injected" if there's no provider (just so it's visible to the user). @@ -145,10 +166,10 @@ export class RunTab extends ViewPlugin { } if (window && window.trustwallet) { - const displayNameInjected = `Injected Provider - TrustWallet` + const displayNameInjected = `Injected Provider - TrustWallet` await addProvider('injected-trustwallet', displayNameInjected, true, false) } - + // VM const titleVM = 'Execution environment is local to Remix. Data is only saved to browser memory and will vanish upon reload.' await addProvider('vm-shanghai', 'Remix VM (Shanghai)', false, true, 'shanghai', 'settingsVMShanghaiMode', titleVM) @@ -163,26 +184,29 @@ export class RunTab extends ViewPlugin { // wallet connect await addProvider('walletconnect', 'WalletConnect', false, false) + // testnet + await addProvider('injected-ephemery-testnet-provider', 'Ephemery Testnet', true, false) + // external provider await addProvider('basic-http-provider', 'Custom - External Http Provider', false, false) await addProvider('hardhat-provider', 'Dev - Hardhat Provider', false, false) await addProvider('ganache-provider', 'Dev - Ganache Provider', false, false) - await addProvider('foundry-provider', 'Dev - Foundry Provider', false, false) - - // injected provider + await addProvider('foundry-provider', 'Dev - Foundry Provider', false, false) + + // injected provider await addProvider('injected-optimism-provider', 'L2 - Optimism Provider', true, false) await addProvider('injected-arbitrum-one-provider', 'L2 - Arbitrum One Provider', true, false) } - writeFile (fileName, content) { + writeFile(fileName, content) { return this.call('fileManager', 'writeFile', fileName, content) } - readFile (fileName) { + readFile(fileName) { return this.call('fileManager', 'readFile', fileName) } - async resolveContractAndAddInstance (contractObject, address) { + async resolveContractAndAddInstance(contractObject, address) { const data = await this.compilersArtefacts.getCompilerAbstract(contractObject.contract.file) this.compilersArtefacts.addResolvedContract(addressToString(address), data) diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index edb09e2ee7..ca1a76a3be 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -1,35 +1,116 @@ -import { PluginManager } from '@remixproject/engine' -import { EventEmitter } from 'events' -import { QueryParams } from '@remix-project/remix-lib' -import { IframePlugin } from '@remixproject/engine-web' -const _paq = window._paq = window._paq || [] +import {PluginManager} from '@remixproject/engine' +import {EventEmitter} from 'events' +import {QueryParams} from '@remix-project/remix-lib' +import {IframePlugin} from '@remixproject/engine-web' +const _paq = (window._paq = window._paq || []) // requiredModule removes the plugin from the plugin manager list on UI -const requiredModules = [ // services + layout views + system views - 'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'locale', - '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', 'injected-trustwallet', 'injected-optimism-provider', 'injected-arbitrum-one-provider', 'vm-custom-fork', 'vm-goerli-fork', 'vm-mainnet-fork', 'vm-sepolia-fork', 'vm-merge', 'vm-london', 'vm-berlin', +const requiredModules = [ + // services + layout views + system views + 'manager', + 'config', + 'compilerArtefacts', + 'compilerMetadata', + 'contextualListener', + 'editor', + 'offsetToLineColumnConverter', + 'network', + 'theme', + 'locale', + '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', + 'injected-trustwallet', + 'injected-optimism-provider', + 'injected-arbitrum-one-provider', + 'injected-ephemery-testnet-provider', + 'vm-custom-fork', + 'vm-goerli-fork', + 'vm-mainnet-fork', + 'vm-sepolia-fork', + 'vm-merge', + 'vm-london', + 'vm-berlin', 'vm-shanghai', - 'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser', 'codeFormatter', 'solidityumlgen', 'contractflattener', 'solidity-script'] + 'compileAndRun', + 'search', + 'recorder', + 'fileDecorator', + 'codeParser', + 'codeFormatter', + 'solidityumlgen', + 'contractflattener', + 'solidity-script' +] // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither'] -const loadLocalPlugins = ["doc-gen", "doc-viewer", "etherscan", "vyper", "solhint", "walletconnect", "circuit-compiler"] +const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'etherscan', 'vyper', 'solhint', 'walletconnect', 'circuit-compiler'] const sensitiveCalls = { - 'fileManager': ['writeFile', 'copyFile', 'rename', 'copyDir'], - 'contentImport': ['resolveAndSave'], - 'web3Provider': ['sendAsync'], + fileManager: ['writeFile', 'copyFile', 'rename', 'copyDir'], + contentImport: ['resolveAndSave'], + web3Provider: ['sendAsync'] } 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', 'injected', 'doc-gen', 'doc-viewer'] + 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', + 'injected-ephemery-testnet-provider', + 'injected', + 'doc-gen', + 'doc-viewer' + ] return nativePlugins.includes(name) || requiredModules.includes(name) } @@ -44,9 +125,7 @@ export function isNative(name) { * @returns {boolean} */ export function canActivate(from, to) { - return ['ethdoc'].includes(from.name) || - isNative(from.name) || - (to && from && from.canActivate && from.canActivate.includes(to.name)) + return ['ethdoc'].includes(from.name) || isNative(from.name) || (to && from && from.canActivate && from.canActivate.includes(to.name)) } export class RemixAppManager extends PluginManager { @@ -72,10 +151,7 @@ export class RemixAppManager extends PluginManager { async deactivatePlugin(name) { const profile = await this.getProfile(name) - const [to, from] = [ - profile, - await this.getProfile(this.requestFrom) - ] + const [to, from] = [profile, await this.getProfile(this.requestFrom)] if (this.canDeactivatePlugin(from, to)) { if (profile.methods.includes('deactivate')) { try { @@ -104,7 +180,10 @@ export class RemixAppManager extends PluginManager { } onPluginActivated(plugin) { - this.pluginLoader.set(plugin, this.actives.filter((plugin) => !this.isDependent(plugin))) + this.pluginLoader.set( + plugin, + this.actives.filter((plugin) => !this.isDependent(plugin)) + ) this.event.emit('activate', plugin) this.emit('activate', plugin) if (!requiredModules.includes(plugin.name)) _paq.push(['trackEvent', 'pluginManager', 'activate', plugin.name]) @@ -121,7 +200,10 @@ export class RemixAppManager extends PluginManager { } onPluginDeactivated(plugin) { - this.pluginLoader.set(plugin, this.actives.filter((plugin) => !this.isDependent(plugin))) + this.pluginLoader.set( + plugin, + this.actives.filter((plugin) => !this.isDependent(plugin)) + ) this.event.emit('deactivate', plugin) _paq.push(['trackEvent', 'pluginManager', 'deactivate', plugin.name]) } @@ -142,7 +224,7 @@ export class RemixAppManager extends PluginManager { plugins = await res.json() plugins = plugins.filter((plugin) => { if (plugin.targets && Array.isArray(plugin.targets) && plugin.targets.length > 0) { - return (plugin.targets.includes('remix')) + return plugin.targets.includes('remix') } return true }) @@ -177,7 +259,7 @@ export class RemixAppManager extends PluginManager { } } - return plugins.map(plugin => { + return plugins.map((plugin) => { if (plugin.name === testPluginName) plugin.url = testPluginUrl return new IframePlugin(plugin) }) @@ -249,13 +331,17 @@ class PluginLoader { const saved = actives.filter((name) => !this.donotAutoReload.includes(name)) localStorage.setItem('workspace', JSON.stringify(saved)) }, - get: () => { return JSON.parse(localStorage.getItem('workspace')) } + get: () => { + return JSON.parse(localStorage.getItem('workspace')) + } } this.loaders.queryParams = { - set: () => { /* Do nothing. */ }, + set: () => { + /* Do nothing. */ + }, get: () => { - const { activate } = queryParams.get() + const {activate} = queryParams.get() if (!activate) return [] return activate.split(',') }