You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
510 lines
20 KiB
510 lines
20 KiB
'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 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'
|
|
|
|
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'
|
|
|
|
const Storage = remixLib.Storage
|
|
const RemixDProvider = require('./app/files/remixDProvider')
|
|
const Config = require('./config')
|
|
|
|
const FileManager = require('./app/files/fileManager')
|
|
const FileProvider = require('./app/files/fileProvider')
|
|
const DGitProvider = require('./app/files/dgitProvider')
|
|
const WorkspaceFileProvider = require('./app/files/workspaceFileProvider')
|
|
|
|
const PluginManagerComponent = require('./app/components/plugin-manager-component')
|
|
|
|
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 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')
|
|
|
|
class AppComponent {
|
|
constructor() {
|
|
this.appManager = new RemixAppManager({})
|
|
this.queryParams = new QueryParams()
|
|
this._components = {}
|
|
// setup storage
|
|
const configStorage = new Storage('config-v0.8:')
|
|
|
|
// load app config
|
|
const config = new Config(configStorage)
|
|
Registry.getInstance().put({ api: config, name: 'config' })
|
|
|
|
// load file system
|
|
this._components.filesProviders = {}
|
|
this._components.filesProviders.browser = new FileProvider('browser')
|
|
Registry.getInstance().put({
|
|
api: this._components.filesProviders.browser,
|
|
name: 'fileproviders/browser'
|
|
})
|
|
this._components.filesProviders.localhost = new RemixDProvider(
|
|
this.appManager
|
|
)
|
|
Registry.getInstance().put({
|
|
api: this._components.filesProviders.localhost,
|
|
name: 'fileproviders/localhost'
|
|
})
|
|
this._components.filesProviders.workspace = new WorkspaceFileProvider()
|
|
Registry.getInstance().put({
|
|
api: this._components.filesProviders.workspace,
|
|
name: 'fileproviders/workspace'
|
|
})
|
|
|
|
Registry.getInstance().put({
|
|
api: this._components.filesProviders,
|
|
name: 'fileproviders'
|
|
})
|
|
}
|
|
|
|
async run() {
|
|
// APP_MANAGER
|
|
const appManager = this.appManager
|
|
const pluginLoader = this.appManager.pluginLoader
|
|
this.panels = {}
|
|
this.workspace = pluginLoader.get()
|
|
this.engine = new RemixEngine()
|
|
this.engine.register(appManager);
|
|
|
|
const matomoDomains = {
|
|
'remix-alpha.ethereum.org': 27,
|
|
'remix-beta.ethereum.org': 25,
|
|
'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
|
|
)
|
|
|
|
const hosts = ['127.0.0.1:8080', '192.168.0.101:8080', 'localhost:8080']
|
|
// workaround for Electron support
|
|
if (!isElectron() && !hosts.includes(window.location.host)) {
|
|
// Oops! Accidentally trigger refresh or bookmark.
|
|
window.onbeforeunload = function () {
|
|
return 'Are you sure you want to leave?'
|
|
}
|
|
}
|
|
|
|
// SERVICES
|
|
// ----------------- gist service ---------------------------------
|
|
this.gistHandler = new GistHandler()
|
|
// ----------------- theme service ---------------------------------
|
|
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' })
|
|
|
|
// ----------------- editor service ----------------------------
|
|
const editor = new Editor() // wrapper around ace editor
|
|
Registry.getInstance().put({ api: editor, name: 'editor' })
|
|
editor.event.register('requiringToSaveCurrentfile', () =>
|
|
fileManager.saveCurrentFile()
|
|
)
|
|
|
|
// ----------------- fileManager service ----------------------------
|
|
const fileManager = new FileManager(editor, appManager)
|
|
Registry.getInstance().put({ api: fileManager, name: 'filemanager' })
|
|
// ----------------- dGit provider ---------------------------------
|
|
const dGitProvider = new DGitProvider()
|
|
|
|
// ----------------- Storage plugin ---------------------------------
|
|
const storagePlugin = new StoragePlugin()
|
|
|
|
// ------- FILE DECORATOR PLUGIN ------------------
|
|
const fileDecorator = new FileDecorator()
|
|
|
|
// ------- CODE FORMAT PLUGIN ------------------
|
|
const codeFormat = new CodeFormat()
|
|
|
|
//----- search
|
|
const search = new SearchPlugin()
|
|
|
|
//---------------- Solidity UML Generator -------------------------
|
|
const solidityumlgen = new SolidityUmlGen(appManager)
|
|
|
|
// ----------------- ContractFlattener ----------------------------
|
|
const contractFlattener = new ContractFlattener()
|
|
|
|
// ----------------- import content service ------------------------
|
|
const contentImport = new CompilerImports()
|
|
|
|
const blockchain = new Blockchain(Registry.getInstance().get('config').api)
|
|
|
|
// ----------------- compilation metadata generation service ---------
|
|
const compilerMetadataGenerator = new CompilerMetadata()
|
|
// ----------------- compilation result service (can keep track of compilation results) ----------------------------
|
|
const compilersArtefacts = new CompilerArtefacts() // store all the compilation results (key represent a compiler name)
|
|
Registry.getInstance().put({
|
|
api: compilersArtefacts,
|
|
name: 'compilersartefacts'
|
|
})
|
|
|
|
// service which fetch contract artifacts from sourve-verify, put artifacts in remix and compile it
|
|
const fetchAndCompile = new FetchAndCompile()
|
|
// ----------------- network service (resolve network id / name) -----
|
|
const networkModule = new NetworkModule(blockchain)
|
|
// ----------------- represent the current selected web3 provider ----
|
|
const web3Provider = new Web3ProviderModule(blockchain)
|
|
const vmProviderCustomFork = new CustomForkVMProvider(blockchain)
|
|
const vmProviderMainnetFork = new MainnetForkVMProvider(blockchain)
|
|
const vmProviderSepoliaFork = new SepoliaForkVMProvider(blockchain)
|
|
const vmProviderGoerliFork = new GoerliForkVMProvider(blockchain)
|
|
const vmProviderShanghai = new ShanghaiVMProvider(blockchain)
|
|
const vmProviderMerge = new MergeVMProvider(blockchain)
|
|
const vmProviderBerlin = new BerlinVMProvider(blockchain)
|
|
const vmProviderLondon = new LondonVMProvider(blockchain)
|
|
const hardhatProvider = new HardhatProvider(blockchain)
|
|
const ganacheProvider = new GanacheProvider(blockchain)
|
|
const foundryProvider = new FoundryProvider(blockchain)
|
|
const externalHttpProvider = new ExternalHttpProvider(blockchain)
|
|
const trustWalletInjectedProvider = new InjectedProviderTrustWallet()
|
|
const defaultInjectedProvider = new InjectedProviderDefault
|
|
const injected0ptimismProvider = new Injected0ptimismProvider()
|
|
const injectedArbitrumOneProvider = new InjectedArbitrumOneProvider()
|
|
// ----------------- convert offset to line/column service -----------
|
|
const offsetToLineColumnConverter = new OffsetToLineColumnConverter()
|
|
Registry.getInstance().put({
|
|
api: offsetToLineColumnConverter,
|
|
name: 'offsettolinecolumnconverter'
|
|
})
|
|
// ----------------- run script after each compilation results -----------
|
|
const compileAndRun = new CompileAndRun()
|
|
// -------------------Terminal----------------------------------------
|
|
makeUdapp(blockchain, compilersArtefacts, domEl => terminal.logHtml(domEl))
|
|
const terminal = new Terminal(
|
|
{ appManager, blockchain },
|
|
{
|
|
getPosition: event => {
|
|
const limitUp = 36
|
|
const limitDown = 20
|
|
const height = window.innerHeight
|
|
let newpos = event.pageY < limitUp ? limitUp : event.pageY
|
|
newpos = newpos < height - limitDown ? newpos : height - limitDown
|
|
return height - newpos
|
|
}
|
|
}
|
|
)
|
|
|
|
const codeParser = new CodeParser(new AstWalker())
|
|
const solidityScript = new SolidityScript()
|
|
|
|
this.notification = new NotificationPlugin()
|
|
|
|
const configPlugin = new ConfigPlugin()
|
|
this.layout = new Layout()
|
|
|
|
const permissionHandler = new PermissionHandlerPlugin()
|
|
|
|
this.engine.register([
|
|
permissionHandler,
|
|
this.layout,
|
|
this.notification,
|
|
this.gistHandler,
|
|
configPlugin,
|
|
blockchain,
|
|
contentImport,
|
|
this.themeModule,
|
|
this.localeModule,
|
|
editor,
|
|
fileManager,
|
|
compilerMetadataGenerator,
|
|
compilersArtefacts,
|
|
networkModule,
|
|
offsetToLineColumnConverter,
|
|
codeParser,
|
|
fileDecorator,
|
|
codeFormat,
|
|
terminal,
|
|
web3Provider,
|
|
compileAndRun,
|
|
fetchAndCompile,
|
|
dGitProvider,
|
|
storagePlugin,
|
|
vmProviderShanghai,
|
|
vmProviderMerge,
|
|
vmProviderBerlin,
|
|
vmProviderLondon,
|
|
vmProviderSepoliaFork,
|
|
vmProviderGoerliFork,
|
|
vmProviderMainnetFork,
|
|
vmProviderCustomFork,
|
|
hardhatProvider,
|
|
ganacheProvider,
|
|
foundryProvider,
|
|
externalHttpProvider,
|
|
defaultInjectedProvider,
|
|
trustWalletInjectedProvider,
|
|
injected0ptimismProvider,
|
|
injectedArbitrumOneProvider,
|
|
this.walkthroughService,
|
|
search,
|
|
solidityumlgen,
|
|
contractFlattener,
|
|
solidityScript
|
|
])
|
|
|
|
// LAYOUT & SYSTEM VIEWS
|
|
const appPanel = new MainPanel()
|
|
Registry.getInstance().put({ api: this.mainview, name: 'mainview' })
|
|
const tabProxy = new TabProxy(fileManager, editor)
|
|
this.engine.register([appPanel, tabProxy])
|
|
|
|
// those views depend on app_manager
|
|
this.menuicons = new VerticalIcons()
|
|
this.sidePanel = new SidePanel()
|
|
this.hiddenPanel = new HiddenPanel()
|
|
|
|
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
|
|
)
|
|
|
|
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 run = new RunTab(
|
|
blockchain,
|
|
Registry.getInstance().get('config').api,
|
|
Registry.getInstance().get('filemanager').api,
|
|
Registry.getInstance().get('editor').api,
|
|
filePanel,
|
|
Registry.getInstance().get('compilersartefacts').api,
|
|
networkModule,
|
|
Registry.getInstance().get('fileproviders/browser').api
|
|
)
|
|
const analysis = new AnalysisTab()
|
|
const debug = new DebuggerTab()
|
|
const test = new TestTab(
|
|
Registry.getInstance().get('filemanager').api,
|
|
Registry.getInstance().get('offsettolinecolumnconverter').api,
|
|
filePanel,
|
|
compileTab,
|
|
appManager,
|
|
contentImport
|
|
)
|
|
|
|
this.engine.register([
|
|
compileTab,
|
|
run,
|
|
debug,
|
|
analysis,
|
|
test,
|
|
filePanel.remixdHandle,
|
|
filePanel.hardhatHandle,
|
|
filePanel.foundryHandle,
|
|
filePanel.truffleHandle,
|
|
filePanel.slitherHandle,
|
|
linkLibraries,
|
|
deployLibraries,
|
|
openZeppelinProxy,
|
|
run.recorder
|
|
])
|
|
|
|
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 }
|
|
}
|
|
}
|
|
|
|
async activate() {
|
|
const queryParams = new QueryParams()
|
|
const params = queryParams.get()
|
|
|
|
try {
|
|
this.engine.register(await this.appManager.registeredPlugins())
|
|
} catch (e) {
|
|
console.log("couldn't register iframe plugins", e.message)
|
|
}
|
|
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(['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(['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()
|
|
}
|
|
)
|
|
|
|
await this.appManager.activatePlugin(['filePanel'])
|
|
// Set workspace after initial activation
|
|
this.appManager.on('editor', 'editorMounted', () => {
|
|
if (Array.isArray(this.workspace)) {
|
|
this.appManager
|
|
.activatePlugin(this.workspace)
|
|
.then(async () => {
|
|
try {
|
|
if (params.deactivate) {
|
|
await this.appManager.deactivatePlugin(
|
|
params.deactivate.split(',')
|
|
)
|
|
}
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
if (params.code && (!params.activate || params.activate.split(',').includes('solidity'))) {
|
|
// if code is given in url we focus on solidity plugin
|
|
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
|
|
) {
|
|
this.menuicons.select(this.workspace[this.workspace.length - 1])
|
|
} else {
|
|
this.appManager.call('tabs', 'focus', 'home')
|
|
}
|
|
}
|
|
|
|
if (params.call) {
|
|
const callDetails = params.call.split('//')
|
|
if (callDetails.length > 1) {
|
|
this.appManager.call('notification', 'toast', `initiating ${callDetails[0]} and calling "${callDetails[1]}" ...`)
|
|
// @todo(remove the timeout when activatePlugin is on 0.3.0)
|
|
await this.appManager.call(...callDetails).catch(console.error)
|
|
}
|
|
}
|
|
|
|
if (params.calls) {
|
|
const calls = params.calls.split("///");
|
|
|
|
// call all functions in the list, one after the other
|
|
for (const call of calls) {
|
|
const callDetails = call.split("//");
|
|
if (callDetails.length > 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 {
|
|
await this.appManager.call(...callDetails)
|
|
} catch (e) {
|
|
console.error(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
.catch(console.error)
|
|
}
|
|
const loadedElement = document.createElement('span')
|
|
loadedElement.setAttribute('data-id', 'apploaded')
|
|
document.body.appendChild(loadedElement)
|
|
})
|
|
|
|
// activate solidity plugin
|
|
this.appManager.activatePlugin(['solidity', 'udapp', 'deploy-libraries', 'link-libraries', 'openzeppelin-proxy'])
|
|
}
|
|
}
|
|
|
|
export default AppComponent
|
|
|