diff --git a/apps/remix-ide/ci/publishIpfs b/apps/remix-ide/ci/publishIpfs index c56a5f37bf..98a5d56729 100755 --- a/apps/remix-ide/ci/publishIpfs +++ b/apps/remix-ide/ci/publishIpfs @@ -6,13 +6,13 @@ console.log('current folder', process.cwd()) const folder = process.cwd() + '/temp_publish_docker'; (async () => { - const host = 'ipfs.komputing.org' // ethdev berlin ipfs node + const host = 'ipfs.remixproject.org' const ipfs = IpfsHttpClient({ host, port: 443, protocol: 'https' }) try { let result = await ipfs.add(globSource(folder, { recursive: true}), { pin: false }) const hash = result.cid.toString() console.log('ipfs://' + hash) - console.log('https://ipfsgw.komputing.org/ipfs/' + hash) + console.log('https://ipfs.remixproject.org/ipfs/' + hash) console.log('https://gateway.ipfs.io/ipfs/' + hash) } catch (e) { console.log(e) diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 8beeae8849..4cb32e75e7 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -16,7 +16,8 @@ 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 FetchAndCompile from './app/compiler/compiler-sourceVerifier-fetchAndCompile' + +import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports } from '@remix-project/core-plugin' import migrateFileSystem from './migrateFileSystem' @@ -25,7 +26,7 @@ const csjs = require('csjs-inject') const yo = require('yo-yo') const remixLib = require('@remix-project/remix-lib') const registry = require('./global/registry') -const { OffsetToLineColumnConverter } = require('./lib/offsetToLineColumnConverter') + const QueryParams = require('./lib/query-params') const Storage = remixLib.Storage const RemixDProvider = require('./app/files/remixDProvider') @@ -38,13 +39,10 @@ const FileProvider = require('./app/files/fileProvider') const DGitProvider = require('./app/files/dgitProvider') const WorkspaceFileProvider = require('./app/files/workspaceFileProvider') const toolTip = require('./app/ui/tooltip') -const CompilerMetadata = require('./app/files/compiler-metadata') -const CompilerImport = require('./app/compiler/compiler-imports') const Blockchain = require('./blockchain/blockchain.js') const PluginManagerComponent = require('./app/components/plugin-manager-component') -const CompilersArtefacts = require('./app/compiler/compiler-artefacts') const CompileTab = require('./app/tabs/compile-tab') const SettingsTab = require('./app/tabs/settings-tab') @@ -262,14 +260,14 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const dGitProvider = new DGitProvider() // ----------------- import content service ------------------------ - const contentImport = new CompilerImport(fileManager) + const contentImport = new CompilerImports() const blockchain = new Blockchain(registry.get('config').api) // ----------------- compilation metadata generation service --------- - const compilerMetadataGenerator = new CompilerMetadata(blockchain, fileManager, registry.get('config').api) + const compilerMetadataGenerator = new CompilerMetadata() // ----------------- compilation result service (can keep track of compilation results) ---------------------------- - const compilersArtefacts = new CompilersArtefacts() // store all the compilation results (key represent a compiler name) + const compilersArtefacts = new CompilerArtefacts() // store all the compilation results (key represent a compiler name) registry.put({ api: compilersArtefacts, name: 'compilersartefacts' }) // service which fetch contract artifacts from sourve-verify, put artifacts in remix and compile it @@ -458,11 +456,11 @@ Please make a backup of your contracts and start using http://remix.ethereum.org console.log('couldn\'t register iframe plugins', e.message) } - await appManager.activatePlugin(['contentImport', 'theme', 'editor', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter']) + await appManager.activatePlugin(['theme', 'editor', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter']) await appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs']) await appManager.activatePlugin(['sidePanel']) // activating host plugin separately await appManager.activatePlugin(['home']) - await appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'filePanel', 'settings', 'contextualListener', 'terminal', 'fetchAndCompile']) + await appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'filePanel', 'settings', 'contextualListener', 'terminal', 'fetchAndCompile', 'contentImport']) const queryParams = new QueryParams() const params = queryParams.get() diff --git a/apps/remix-ide/src/app/compiler/compiler-abstract.js b/apps/remix-ide/src/app/compiler/compiler-abstract.js deleted file mode 100644 index fcfb32a827..0000000000 --- a/apps/remix-ide/src/app/compiler/compiler-abstract.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict' -var remixLib = require('@remix-project/remix-lib') -var txHelper = remixLib.execution.txHelper - -module.exports = class CompilerAbstract { - constructor (languageversion, data, source) { - this.languageversion = languageversion - this.data = data - this.source = source // source code - } - - getContracts () { - return this.data.contracts - } - - getContract (name) { - return txHelper.getContract(name, this.data.contracts) - } - - visitContracts (calllback) { - return txHelper.visitContracts(this.data.contracts, calllback) - } - - getData () { - return this.data - } - - getAsts () { - return this.data.sources // ast - } - - getSourceName (fileIndex) { - if (this.data && this.data.sources) { - return Object.keys(this.data.sources)[fileIndex] - } else if (Object.keys(this.source.sources).length === 1) { - // if we don't have ast, we return the only one filename present. - const sourcesArray = Object.keys(this.source.sources) - return sourcesArray[0] - } - return null - } - - getSourceCode () { - return this.source - } -} diff --git a/apps/remix-ide/src/app/compiler/compiler-imports.js b/apps/remix-ide/src/app/compiler/compiler-imports.js deleted file mode 100644 index 0e72bb425d..0000000000 --- a/apps/remix-ide/src/app/compiler/compiler-imports.js +++ /dev/null @@ -1,169 +0,0 @@ -'use strict' -import { Plugin } from '@remixproject/engine' -import * as packageJson from '../../../../../package.json' -import { RemixURLResolver } from '@remix-project/remix-url-resolver' -const remixTests = require('@remix-project/remix-tests') -const globalRegistry = require('../../global/registry') -const addTooltip = require('../ui/tooltip') -const async = require('async') - -const profile = { - name: 'contentImport', - displayName: 'content import', - version: packageJson.version, - methods: ['resolve', 'resolveAndSave', 'isExternalUrl'] -} - -module.exports = class CompilerImports extends Plugin { - constructor (fileManager) { - super(profile) - this.fileManager = fileManager - // const token = await this.call('settings', 'getGithubAccessToken') - const token = globalRegistry.get('config').api.get('settings/gist-access-token') // TODO replace with the plugin call above https://github.com/ethereum/remix-ide/issues/2288 - const protocol = window.location.protocol - this.urlResolver = new RemixURLResolver(token, protocol) - this.previouslyHandled = {} // cache import so we don't make the request at each compilation. - } - - isRelativeImport (url) { - return /^([^/]+)/.exec(url) - } - - isExternalUrl (url) { - const handlers = this.urlResolver.getHandlers() - return handlers.some(handler => handler.match(url)) - } - - /** - * resolve the content of @arg url. This only resolves external URLs. - * - * @param {String} url - external URL of the content. can be basically anything like raw HTTP, ipfs URL, github address etc... - * @returns {Promise} - { content, cleanUrl, type, url } - */ - resolve (url) { - return new Promise((resolve, reject) => { - this.import(url, null, (error, content, cleanUrl, type, url) => { - if (error) return reject(error) - resolve({ content, cleanUrl, type, url }) - }) - }) - } - - async import (url, force, loadingCb, cb) { - if (typeof force !== 'boolean') { - const temp = loadingCb - loadingCb = force - cb = temp - force = false - } - if (!loadingCb) loadingCb = () => {} - if (!cb) cb = () => {} - - var self = this - if (force) delete this.previouslyHandled[url] - var imported = this.previouslyHandled[url] - if (imported) { - return cb(null, imported.content, imported.cleanUrl, imported.type, url) - } - - let resolved - try { - resolved = await this.urlResolver.resolve(url) - const { content, cleanUrl, type } = resolved - self.previouslyHandled[url] = { - content, - cleanUrl, - type - } - cb(null, content, cleanUrl, type, url) - } catch (e) { - return cb(new Error('not found ' + url)) - } - } - - importExternal (url, targetPath, cb) { - this.import(url, - // TODO: move to an event that is generated, the UI shouldn't be here - (loadingMsg) => { addTooltip(loadingMsg) }, - (error, content, cleanUrl, type, url) => { - if (error) return cb(error) - if (this.fileManager) { - const provider = this.fileManager.currentFileProvider() - const path = targetPath || type + '/' + cleanUrl - if (provider) provider.addExternal('.deps/' + path, content, url) - } - cb(null, content) - }) - } - - /** - * import the content of @arg url. - * first look in the browser localstorage (browser explorer) or locahost explorer. if the url start with `browser/*` or `localhost/*` - * then check if the @arg url is located in the localhost, in the node_modules or installed_contracts folder - * then check if the @arg url match any external url - * - * @param {String} url - URL of the content. can be basically anything like file located in the browser explorer, in the localhost explorer, raw HTTP, github address etc... - * @param {String} targetPath - (optional) internal path where the content should be saved to - * @returns {Promise} - string content - */ - resolveAndSave (url, targetPath) { - return new Promise((resolve, reject) => { - if (url.indexOf('remix_tests.sol') !== -1) resolve(remixTests.assertLibCode) - if (!this.fileManager) { - // fallback to just resolving the file, it won't be saved in file manager - return this.importExternal(url, targetPath, (error, content) => { - if (error) return reject(error) - resolve(content) - }) - } - var provider = this.fileManager.fileProviderOf(url) - if (provider) { - if (provider.type === 'localhost' && !provider.isConnected()) { - return reject(new Error(`file provider ${provider.type} not available while trying to resolve ${url}`)) - } - provider.exists(url).then(exist => { - /* - if the path is absolute and the file does not exist, we can stop here - Doesn't make sense to try to resolve "localhost/node_modules/localhost/node_modules/" and we'll end in an infinite loop. - */ - if (!exist && url.startsWith('browser/')) return reject(new Error(`not found ${url}`)) - if (!exist && url.startsWith('localhost/')) return reject(new Error(`not found ${url}`)) - - if (exist) { - return provider.get(url, (error, content) => { - if (error) return reject(error) - resolve(content) - }) - } - - // try to resolve localhost modules (aka truffle imports) - e.g from the node_modules folder - const localhostProvider = this.fileManager.getProvider('localhost') - if (localhostProvider.isConnected()) { - var splitted = /([^/]+)\/(.*)$/g.exec(url) - return async.tryEach([ - (cb) => { this.resolveAndSave('localhost/installed_contracts/' + url).then((result) => cb(null, result)).catch((error) => cb(error.message)) }, - (cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.resolveAndSave('localhost/installed_contracts/' + splitted[1] + '/contracts/' + splitted[2]).then((result) => cb(null, result)).catch((error) => cb(error.message)) } }, - (cb) => { this.resolveAndSave('localhost/node_modules/' + url).then((result) => cb(null, result)).catch((error) => cb(error.message)) }, - (cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.resolveAndSave('localhost/node_modules/' + splitted[1] + '/contracts/' + splitted[2]).then((result) => cb(null, result)).catch((error) => cb(error.message)) } }], - (error, result) => { - if (error) { - return this.importExternal(url, targetPath, (error, content) => { - if (error) return reject(error) - resolve(content) - }) - } - resolve(result) - }) - } - - this.importExternal(url, targetPath, (error, content) => { - if (error) return reject(error) - resolve(content) - }) - }).catch(error => { - return reject(error) - }) - } - }) - } -} diff --git a/apps/remix-ide/src/app/compiler/compiler-input.js b/apps/remix-ide/src/app/compiler/compiler-input.js deleted file mode 100644 index a0be3c499d..0000000000 --- a/apps/remix-ide/src/app/compiler/compiler-input.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict' - -module.exports = (sources, opts) => { - return JSON.stringify({ - language: 'Solidity', - sources: sources, - settings: { - optimizer: { - enabled: opts.optimize === true || opts.optimize === 1, - runs: 200 - }, - libraries: opts.libraries, - outputSelection: { - '*': { - '': ['ast'], - '*': ['abi', 'metadata', 'devdoc', 'userdoc', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates'] - } - } - } - }) -} diff --git a/apps/remix-ide/src/app/files/compiler-metadata.js b/apps/remix-ide/src/app/files/compiler-metadata.js deleted file mode 100644 index fe4dfc3c43..0000000000 --- a/apps/remix-ide/src/app/files/compiler-metadata.js +++ /dev/null @@ -1,148 +0,0 @@ -'use strict' -import { Plugin } from '@remixproject/engine' -import * as packageJson from '../../../../../package.json' -import { joinPath } from '../../lib/helper' -var CompilerAbstract = require('../compiler/compiler-abstract') - -const profile = { - name: 'compilerMetadata', - methods: ['deployMetadataOf'], - events: [], - version: packageJson.version -} - -class CompilerMetadata extends Plugin { - constructor (blockchain, fileManager, config) { - super(profile) - this.blockchain = blockchain - this.fileManager = fileManager - this.config = config - this.networks = ['VM:-', 'main:1', 'ropsten:3', 'rinkeby:4', 'kovan:42', 'görli:5', 'Custom'] - this.innerPath = 'artifacts' - } - - _JSONFileName (path, contractName) { - return joinPath(path, this.innerPath, contractName + '.json') - } - - _MetadataFileName (path, contractName) { - return joinPath(path, this.innerPath, contractName + '_metadata.json') - } - - onActivation () { - var self = this - this.on('solidity', 'compilationFinished', (file, source, languageVersion, data) => { - if (!self.config.get('settings/generate-contract-metadata')) return - const compiler = new CompilerAbstract(languageVersion, data, source) - var provider = self.fileManager.fileProviderOf(source.target) - var path = self.fileManager.extractPathOf(source.target) - if (provider) { - compiler.visitContracts((contract) => { - if (contract.file !== source.target) return - - var fileName = self._JSONFileName(path, contract.name) - var metadataFileName = self._MetadataFileName(path, contract.name) - provider.get(fileName, (error, content) => { - if (!error) { - content = content || '{}' - var metadata - try { - metadata = JSON.parse(content) - } catch (e) { - console.log(e) - } - - var deploy = metadata.deploy || {} - self.networks.forEach((network) => { - deploy[network] = self._syncContext(contract, deploy[network] || {}) - }) - - let parsedMetadata - try { - parsedMetadata = JSON.parse(contract.object.metadata) - } catch (e) { - console.log(e) - } - if (parsedMetadata) provider.set(metadataFileName, JSON.stringify(parsedMetadata, null, '\t')) - - var data = { - deploy, - data: { - bytecode: contract.object.evm.bytecode, - deployedBytecode: contract.object.evm.deployedBytecode, - gasEstimates: contract.object.evm.gasEstimates, - methodIdentifiers: contract.object.evm.methodIdentifiers - }, - abi: contract.object.abi - } - - provider.set(fileName, JSON.stringify(data, null, '\t')) - } - }) - }) - } - }) - } - - _syncContext (contract, metadata) { - var linkReferences = metadata.linkReferences - var autoDeployLib = metadata.autoDeployLib - if (!linkReferences) linkReferences = {} - if (autoDeployLib === undefined) autoDeployLib = true - - for (var libFile in contract.object.evm.bytecode.linkReferences) { - if (!linkReferences[libFile]) linkReferences[libFile] = {} - for (var lib in contract.object.evm.bytecode.linkReferences[libFile]) { - if (!linkReferences[libFile][lib]) { - linkReferences[libFile][lib] = '
' - } - } - } - metadata.linkReferences = linkReferences - metadata.autoDeployLib = autoDeployLib - return metadata - } - - // TODO: is only called by dropdownLogic and can be moved there - deployMetadataOf (contractName, fileLocation) { - return new Promise((resolve, reject) => { - var provider - let path - if (fileLocation) { - provider = this.fileManager.fileProviderOf(fileLocation) - path = fileLocation.split('/') - path.pop() - path = path.join('/') - } else { - provider = this.fileManager.currentFileProvider() - path = this.fileManager.currentPath() - } - - if (provider) { - this.blockchain.detectNetwork((err, { id, name } = {}) => { - if (err) { - console.log(err) - reject(err) - } else { - var fileName = this._JSONFileName(path, contractName) - provider.get(fileName, (error, content) => { - if (error) return reject(error) - if (!content) return resolve() - try { - var metadata = JSON.parse(content) - metadata = metadata.deploy || {} - return resolve(metadata[name + ':' + id] || metadata[name] || metadata[id] || metadata[name.toLowerCase() + ':' + id] || metadata[name.toLowerCase()]) - } catch (e) { - reject(e.message) - } - }) - } - }) - } else { - reject(new Error(`Please select the folder in the file explorer where the metadata of ${contractName} can be found`)) - } - }) - } -} - -module.exports = CompilerMetadata diff --git a/apps/remix-ide/src/app/files/dgitProvider.js b/apps/remix-ide/src/app/files/dgitProvider.js index ed7d4edb8e..5a2bc6a366 100644 --- a/apps/remix-ide/src/app/files/dgitProvider.js +++ b/apps/remix-ide/src/app/files/dgitProvider.js @@ -27,10 +27,10 @@ class DGitProvider extends Plugin { constructor () { super(profile) this.ipfsconfig = { - host: 'ipfs.komputing.org', + host: 'ipfs.remixproject.org', port: 443, protocol: 'https', - ipfsurl: 'https://ipfsgw.komputing.org/ipfs/' + ipfsurl: 'https://ipfs.remixproject.org/ipfs/' } this.globalIPFSConfig = { host: 'ipfs.io', diff --git a/apps/remix-ide/src/app/files/fileManager.js b/apps/remix-ide/src/app/files/fileManager.js index c789991a9a..9b618a9fe9 100644 --- a/apps/remix-ide/src/app/files/fileManager.js +++ b/apps/remix-ide/src/app/files/fileManager.js @@ -22,7 +22,7 @@ const profile = { icon: 'assets/img/fileManager.webp', permission: true, version: packageJson.version, - methods: ['file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh'], + methods: ['file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName'], kind: 'file-system' } const errorMsg = { @@ -597,6 +597,32 @@ class FileManager extends Plugin { } } + /** + * Async API method getProviderOf + * @param {string} file + * + */ + + async getProviderOf (file) { + const cancall = await this.askUserPermission('getProviderByName') + if (cancall) { + return file ? this.fileProviderOf(file) : this.currentFileProvider() + } + } + + /** + * Async API method getProviderByName + * @param {string} name + * + */ + + async getProviderByName (name) { + const cancall = await this.askUserPermission('getProviderByName') + if (cancall) { + return this.getProvider(name) + } + } + getProvider (name) { return this._deps.filesProviders[name] } diff --git a/apps/remix-ide/src/app/files/fileProvider.js b/apps/remix-ide/src/app/files/fileProvider.js index 5d152ec74b..c789635160 100644 --- a/apps/remix-ide/src/app/files/fileProvider.js +++ b/apps/remix-ide/src/app/files/fileProvider.js @@ -1,6 +1,6 @@ 'use strict' -const CompilerImport = require('../compiler/compiler-imports') +import { CompilerImports } from '@remix-project/core-plugin' const EventManager = require('events') const modalDialogCustom = require('../ui/modal-dialog-custom') const tooltip = require('../ui/tooltip') @@ -44,7 +44,7 @@ class FileProvider { discardChanges (path) { this.remove(path) - const compilerImport = new CompilerImport() + const compilerImport = new CompilerImports() this.providerExternalsStorage.keys().map(value => { if (value.indexOf(path) === 0) { compilerImport.import( diff --git a/apps/remix-ide/src/app/tabs/compile-tab.js b/apps/remix-ide/src/app/tabs/compile-tab.js index 038458e87d..e24d18a949 100644 --- a/apps/remix-ide/src/app/tabs/compile-tab.js +++ b/apps/remix-ide/src/app/tabs/compile-tab.js @@ -2,7 +2,7 @@ import { ViewPlugin } from '@remixproject/engine-web' import * as packageJson from '../../../../../package.json' import publishToStorage from '../../publishToStorage' -import { compile } from '../compiler/compiler-helpers' +import { compile } from '@remix-project/remix-solidity' const EventEmitter = require('events') const $ = require('jquery') diff --git a/apps/remix-ide/src/app/tabs/compileTab/compilerContainer.js b/apps/remix-ide/src/app/tabs/compileTab/compilerContainer.js index 00cf79233d..26a9670a1b 100644 --- a/apps/remix-ide/src/app/tabs/compileTab/compilerContainer.js +++ b/apps/remix-ide/src/app/tabs/compileTab/compilerContainer.js @@ -1,6 +1,6 @@ import toaster from '../../ui/tooltip' -import { canUseWorker, baseURLBin, baseURLWasm, urlFromVersion, pathToURL, promisedMiniXhr } from '../../compiler/compiler-utils' +import { canUseWorker, baseURLBin, baseURLWasm, urlFromVersion, pathToURL, promisedMiniXhr } from '@remix-project/remix-solidity' const yo = require('yo-yo') const helper = require('../../../lib/helper') const addTooltip = require('../../ui/tooltip') diff --git a/apps/remix-ide/src/app/tabs/runTab/model/dropdownlogic.js b/apps/remix-ide/src/app/tabs/runTab/model/dropdownlogic.js index 2ee225fef3..386f654775 100644 --- a/apps/remix-ide/src/app/tabs/runTab/model/dropdownlogic.js +++ b/apps/remix-ide/src/app/tabs/runTab/model/dropdownlogic.js @@ -1,6 +1,6 @@ +import { CompilerAbstract } from '@remix-project/remix-solidity' const remixLib = require('@remix-project/remix-lib') const txHelper = remixLib.execution.txHelper -const CompilerAbstract = require('../../../compiler/compiler-abstract') const EventManager = remixLib.EventManager const _paq = window._paq = window._paq || [] diff --git a/apps/remix-ide/src/app/tabs/settings-tab.js b/apps/remix-ide/src/app/tabs/settings-tab.js index 4e264b9100..edcd3cafdc 100644 --- a/apps/remix-ide/src/app/tabs/settings-tab.js +++ b/apps/remix-ide/src/app/tabs/settings-tab.js @@ -8,7 +8,7 @@ const globalRegistry = require('../../global/registry') const profile = { name: 'settings', displayName: 'Settings', - methods: ['getGithubAccessToken'], + methods: ['get'], events: [], icon: 'assets/img/settings.webp', description: 'Remix-IDE settings', @@ -52,8 +52,8 @@ module.exports = class SettingsTab extends ViewPlugin { ) } - getGithubAccessToken () { - return this.config.get('settings/gist-access-token') + get (key) { + return this.config.get(key) } updateMatomoAnalyticsChoice (isChecked) { diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index b4527f1151..b5c2c2fafd 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -1,7 +1,6 @@ import { ViewPlugin } from '@remixproject/engine-web' -import { canUseWorker, urlFromVersion } from '../compiler/compiler-utils' import { removeMultipleSlashes, removeTrailingSlashes } from '../../lib/helper' - +import { canUseWorker, urlFromVersion } from '@remix-project/remix-solidity' var yo = require('yo-yo') var async = require('async') var tooltip = require('../ui/tooltip') diff --git a/apps/remix-ide/src/app/ui/landing-page/landing-page.js b/apps/remix-ide/src/app/ui/landing-page/landing-page.js index 1fa8b0dba2..8652017b2a 100644 --- a/apps/remix-ide/src/app/ui/landing-page/landing-page.js +++ b/apps/remix-ide/src/app/ui/landing-page/landing-page.js @@ -1,12 +1,12 @@ import * as packageJson from '../../../../../../package.json' import { ViewPlugin } from '@remixproject/engine-web' import { migrateToWorkspace } from '../../../migrateFileSystem' +import { CompilerImports } from '@remix-project/core-plugin' import JSZip from 'jszip' const yo = require('yo-yo') const csjs = require('csjs-inject') const globalRegistry = require('../../../global/registry') -const CompilerImport = require('../../compiler/compiler-imports') const modalDialogCustom = require('../modal-dialog-custom') const modalDialog = require('../modaldialog') const tooltip = require('../tooltip') @@ -240,7 +240,7 @@ export class LandingPage extends ViewPlugin { render () { const load = (service, item, examples, info) => { - const compilerImport = new CompilerImport() + const compilerImport = new CompilerImports() const fileProviders = globalRegistry.get('fileproviders').api const msg = yo`
diff --git a/apps/remix-ide/src/lib/cmdInterpreterAPI.js b/apps/remix-ide/src/lib/cmdInterpreterAPI.js index d132f13107..9c79cae25b 100644 --- a/apps/remix-ide/src/lib/cmdInterpreterAPI.js +++ b/apps/remix-ide/src/lib/cmdInterpreterAPI.js @@ -1,9 +1,9 @@ 'use strict' +import { CompilerImports } from '@remix-project/core-plugin' var yo = require('yo-yo') var async = require('async') var EventManager = require('../lib/events') -var CompilerImport = require('../app/compiler/compiler-imports') var toolTip = require('../app/ui/tooltip') var globalRegistry = require('../global/registry') var SourceHighlighter = require('../app/editor/sourceHighlighter') @@ -18,7 +18,7 @@ class CmdInterpreterAPI { self._components.registry = localRegistry || globalRegistry self._components.terminal = terminal self._components.sourceHighlighter = new SourceHighlighter() - self._components.fileImport = new CompilerImport() + self._components.fileImport = new CompilerImports() self._components.gistHandler = new GistHandler() self._deps = { fileManager: self._components.registry.get('filemanager').api, diff --git a/apps/remix-ide/src/lib/publishOnIpfs.js b/apps/remix-ide/src/lib/publishOnIpfs.js index 52a55a02e7..07f8256540 100644 --- a/apps/remix-ide/src/lib/publishOnIpfs.js +++ b/apps/remix-ide/src/lib/publishOnIpfs.js @@ -4,7 +4,7 @@ const async = require('async') const IpfsClient = require('ipfs-mini') const ipfsNodes = [ - new IpfsClient({ host: 'ipfs.komputing.org', port: 443, protocol: 'https' }), + new IpfsClient({ host: 'ipfs.remixproject.org', port: 443, protocol: 'https' }), new IpfsClient({ host: 'ipfs.infura.io', port: 5001, protocol: 'https' }), new IpfsClient({ host: '127.0.0.1', port: 5001, protocol: 'http' }) ] diff --git a/libs/remix-core-plugin/.eslintrc b/libs/remix-core-plugin/.eslintrc new file mode 100644 index 0000000000..ab8f38339c --- /dev/null +++ b/libs/remix-core-plugin/.eslintrc @@ -0,0 +1 @@ +{ "extends": "../../.eslintrc", "rules": {}, "ignorePatterns": ["!**/*"] } diff --git a/libs/remix-core-plugin/README.md b/libs/remix-core-plugin/README.md new file mode 100644 index 0000000000..fc60297f57 --- /dev/null +++ b/libs/remix-core-plugin/README.md @@ -0,0 +1,3 @@ +# remix-core-plugin-core-plugin + +This library was generated with [Nx](https://nx.dev). diff --git a/libs/remix-core-plugin/package.json b/libs/remix-core-plugin/package.json new file mode 100644 index 0000000000..dcdc862128 --- /dev/null +++ b/libs/remix-core-plugin/package.json @@ -0,0 +1,12 @@ +{ + "name": "@remix-project/core-plugin", + "version": "0.0.1", + "description": "This library was generated with [Nx](https://nx.dev).", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Remix Team", + "license": "ISC" + } + \ No newline at end of file diff --git a/libs/remix-core-plugin/src/index.ts b/libs/remix-core-plugin/src/index.ts new file mode 100644 index 0000000000..73c98a6181 --- /dev/null +++ b/libs/remix-core-plugin/src/index.ts @@ -0,0 +1,5 @@ +export { OffsetToLineColumnConverter } from './lib/offset-line-to-column-converter' +export { CompilerMetadata } from './lib/compiler-metadata' +export { FetchAndCompile } from './lib/compiler-fetch-and-compile' +export { CompilerImports } from './lib/compiler-content-imports' +export { CompilerArtefacts } from './lib/compiler-artefacts' diff --git a/apps/remix-ide/src/app/compiler/compiler-artefacts.js b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts similarity index 92% rename from apps/remix-ide/src/app/compiler/compiler-artefacts.js rename to libs/remix-core-plugin/src/lib/compiler-artefacts.ts index 68b1cad9bd..47eb1d519b 100644 --- a/apps/remix-ide/src/app/compiler/compiler-artefacts.js +++ b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts @@ -1,16 +1,17 @@ 'use strict' import { Plugin } from '@remixproject/engine' -import * as packageJson from '../../../../../package.json' -import CompilerAbstract from './compiler-abstract' +import { CompilerAbstract } from '@remix-project/remix-solidity' const profile = { name: 'compilerArtefacts', - methods: [], + methods: ['get', 'addResolvedContract'], events: [], - version: packageJson.version + version: '0.0.1' } -module.exports = class CompilerArtefacts extends Plugin { +export class CompilerArtefacts extends Plugin { + compilersArtefactsPerFile: any + compilersArtefacts: any constructor () { super(profile) this.compilersArtefacts = {} diff --git a/libs/remix-core-plugin/src/lib/compiler-content-imports.ts b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts new file mode 100644 index 0000000000..ea4eae6958 --- /dev/null +++ b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts @@ -0,0 +1,175 @@ +'use strict' +import { Plugin } from '@remixproject/engine' +import { RemixURLResolver } from '@remix-project/remix-url-resolver' +const remixTests = require('@remix-project/remix-tests') +const async = require('async') + +const profile = { + name: 'contentImport', + displayName: 'content import', + version: '0.0.1', + methods: ['resolve', 'resolveAndSave', 'isExternalUrl'] +} + +export class CompilerImports extends Plugin { + previouslyHandled: {} + urlResolver: any + constructor () { + super(profile) + this.urlResolver = new RemixURLResolver() + this.previouslyHandled = {} // cache import so we don't make the request at each compilation. + } + + async setToken () { + const protocol = typeof window !== 'undefined' && window.location.protocol + const token = await this.call('settings', 'get', 'settings/gist-access-token') + this.urlResolver.setGistToken(token, protocol) + } + + isRelativeImport (url) { + return /^([^/]+)/.exec(url) + } + + isExternalUrl (url) { + const handlers = this.urlResolver.getHandlers() + return handlers.some(handler => handler.match(url)) + } + + /** + * resolve the content of @arg url. This only resolves external URLs. + * + * @param {String} url - external URL of the content. can be basically anything like raw HTTP, ipfs URL, github address etc... + * @returns {Promise} - { content, cleanUrl, type, url } + */ + resolve (url) { + return new Promise((resolve, reject) => { + this.import(url, null, (error, content, cleanUrl, type, url) => { + if (error) return reject(error) + resolve({ content, cleanUrl, type, url }) + }, null) + }) + } + + async import (url, force, loadingCb, cb) { + if (typeof force !== 'boolean') { + const temp = loadingCb + loadingCb = force + cb = temp + force = false + } + if (!loadingCb) loadingCb = () => {} + if (!cb) cb = () => {} + + var self = this + if (force) delete this.previouslyHandled[url] + var imported = this.previouslyHandled[url] + if (imported) { + return cb(null, imported.content, imported.cleanUrl, imported.type, url) + } + + let resolved + try { + await this.setToken() + resolved = await this.urlResolver.resolve(url) + const { content, cleanUrl, type } = resolved + self.previouslyHandled[url] = { + content, + cleanUrl, + type + } + cb(null, content, cleanUrl, type, url) + } catch (e) { + return cb(new Error('not found ' + url)) + } + } + + importExternal (url, targetPath, cb) { + this.import(url, + // TODO: handle this event + (loadingMsg) => { this.emit('message', loadingMsg) }, + async (error, content, cleanUrl, type, url) => { + if (error) return cb(error) + try { + const provider = await this.call('fileManager', 'getProviderOf', null) + const path = targetPath || type + '/' + cleanUrl + if (provider) provider.addExternal('.deps/' + path, content, url) + } catch (err) { + + } + cb(null, content) + }, null) + } + + /** + * import the content of @arg url. + * first look in the browser localstorage (browser explorer) or locahost explorer. if the url start with `browser/*` or `localhost/*` + * then check if the @arg url is located in the localhost, in the node_modules or installed_contracts folder + * then check if the @arg url match any external url + * + * @param {String} url - URL of the content. can be basically anything like file located in the browser explorer, in the localhost explorer, raw HTTP, github address etc... + * @param {String} targetPath - (optional) internal path where the content should be saved to + * @returns {Promise} - string content + */ + resolveAndSave (url, targetPath) { + return new Promise((resolve, reject) => { + if (url.indexOf('remix_tests.sol') !== -1) resolve(remixTests.assertLibCode) + this.call('fileManager', 'getProviderOf', url).then((provider) => { + if (provider) { + if (provider.type === 'localhost' && !provider.isConnected()) { + return reject(new Error(`file provider ${provider.type} not available while trying to resolve ${url}`)) + } + provider.exists(url).then(exist => { + /* + if the path is absolute and the file does not exist, we can stop here + Doesn't make sense to try to resolve "localhost/node_modules/localhost/node_modules/" and we'll end in an infinite loop. + */ + if (!exist && url.startsWith('browser/')) return reject(new Error(`not found ${url}`)) + if (!exist && url.startsWith('localhost/')) return reject(new Error(`not found ${url}`)) + + if (exist) { + return provider.get(url, (error, content) => { + if (error) return reject(error) + resolve(content) + }) + } + + // try to resolve localhost modules (aka truffle imports) - e.g from the node_modules folder + this.call('fileManager', 'getProviderByName', 'localhost').then((localhostProvider) => { + if (localhostProvider.isConnected()) { + var splitted = /([^/]+)\/(.*)$/g.exec(url) + return async.tryEach([ + (cb) => { this.resolveAndSave('localhost/installed_contracts/' + url, null).then((result) => cb(null, result)).catch((error) => cb(error.message)) }, + // eslint-disable-next-line standard/no-callback-literal + (cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.resolveAndSave('localhost/installed_contracts/' + splitted[1] + '/contracts/' + splitted[2], null).then((result) => cb(null, result)).catch((error) => cb(error.message)) } }, + (cb) => { this.resolveAndSave('localhost/node_modules/' + url, null).then((result) => cb(null, result)).catch((error) => cb(error.message)) }, + // eslint-disable-next-line standard/no-callback-literal + (cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.resolveAndSave('localhost/node_modules/' + splitted[1] + '/contracts/' + splitted[2], null).then((result) => cb(null, result)).catch((error) => cb(error.message)) } }], + (error, result) => { + if (error) { + return this.importExternal(url, targetPath, (error, content) => { + if (error) return reject(error) + resolve(content) + }) + } + resolve(result) + }) + } + this.importExternal(url, targetPath, (error, content) => { + if (error) return reject(error) + resolve(content) + }) + }) + }).catch(error => { + return reject(error) + }) + } + }).catch(() => { + // fallback to just resolving the file, it won't be saved in file manager + return this.importExternal(url, targetPath, (error, content) => { + if (error) return reject(error) + resolve(content) + }) + }) + }) + } +} diff --git a/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js b/libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts similarity index 80% rename from apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js rename to libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts index 4a513e2129..e7769b7b04 100644 --- a/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js +++ b/libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts @@ -1,18 +1,19 @@ -import * as packageJson from '../../../../../package.json' + import { Plugin } from '@remixproject/engine' -import { compile } from './compiler-helpers' -import globalRegistry from '../../global/registry' +import { compile } from '@remix-project/remix-solidity' +import { util } from '@remix-project/remix-lib' -import remixLib from '@remix-project/remix-lib' const ethutil = require('ethereumjs-util') const profile = { name: 'fetchAndCompile', methods: ['resolve'], - version: packageJson.version + version: '0.0.1' } -export default class FetchAndCompile extends Plugin { +export class FetchAndCompile extends Plugin { + unresolvedAddresses: any[] + sourceVerifierNetWork: string[] constructor () { super(profile) this.unresolvedAddresses = [] @@ -32,11 +33,10 @@ export default class FetchAndCompile extends Plugin { */ async resolve (contractAddress, codeAtAddress, targetPath) { contractAddress = ethutil.toChecksumAddress(contractAddress) - const compilersartefacts = globalRegistry.get('compilersartefacts').api - const localCompilation = () => compilersartefacts.get(contractAddress) ? compilersartefacts.get(contractAddress) : compilersartefacts.get('__last') ? compilersartefacts.get('__last') : null + const localCompilation = async () => await this.call('compilerArtefacts', 'get', contractAddress) ? await this.call('compilerArtefacts', 'get', contractAddress) : await this.call('compilerArtefacts', 'get', '__last') ? await this.call('compilerArtefacts', 'get', '__last') : null - const resolved = compilersartefacts.get(contractAddress) + const resolved = await this.call('compilerArtefacts', 'get', contractAddress) if (resolved) return resolved if (this.unresolvedAddresses.includes(contractAddress)) return localCompilation() @@ -53,15 +53,15 @@ export default class FetchAndCompile extends Plugin { if (!this.sourceVerifierNetWork.includes(network.name)) return localCompilation() // check if the contract if part of the local compilation result - const compilation = localCompilation() + const compilation = await localCompilation() if (compilation) { let found = false compilation.visitContracts((contract) => { - found = remixLib.util.compareByteCode('0x' + contract.object.evm.deployedBytecode.object, codeAtAddress) + found = util.compareByteCode('0x' + contract.object.evm.deployedBytecode.object, codeAtAddress) return found }) if (found) { - compilersartefacts.addResolvedContract(contractAddress, compilation) + await this.call('compilerArtefacts', 'addResolvedContract', contractAddress, compilation) setTimeout(_ => this.emit('usingLocalCompilation', contractAddress), 0) return compilation } @@ -118,8 +118,8 @@ export default class FetchAndCompile extends Plugin { const compData = await compile( compilationTargets, settings, - (url, cb) => this.call('contentImport', 'resolveAndSave', url).then((result) => cb(null, result)).catch((error) => cb(error.message))) - compilersartefacts.addResolvedContract(contractAddress, compData) + async (url, cb) => await this.call('contentImport', 'resolveAndSave', url).then((result) => cb(null, result)).catch((error) => cb(error.message))) + await this.call('compilerArtefacts', 'addResolvedContract', contractAddress, compData) return compData } catch (e) { this.unresolvedAddresses.push(contractAddress) diff --git a/libs/remix-core-plugin/src/lib/compiler-metadata.ts b/libs/remix-core-plugin/src/lib/compiler-metadata.ts new file mode 100644 index 0000000000..d194c0281d --- /dev/null +++ b/libs/remix-core-plugin/src/lib/compiler-metadata.ts @@ -0,0 +1,145 @@ +'use strict' +import { Plugin } from '@remixproject/engine' +import { CompilerAbstract } from '@remix-project/remix-solidity' + +const profile = { + name: 'compilerMetadata', + methods: ['deployMetadataOf'], + events: [], + version: '0.0.1' +} + +export class CompilerMetadata extends Plugin { + networks: string[] + innerPath: string + constructor () { + super(profile) + this.networks = ['VM:-', 'main:1', 'ropsten:3', 'rinkeby:4', 'kovan:42', 'görli:5', 'Custom'] + this.innerPath = 'artifacts' + } + + _JSONFileName (path, contractName) { + return this.joinPath(path, this.innerPath, contractName + '.json') + } + + _MetadataFileName (path, contractName) { + return this.joinPath(path, this.innerPath, contractName + '_metadata.json') + } + + onActivation () { + var self = this + this.on('solidity', 'compilationFinished', async (file, source, languageVersion, data) => { + if (!await this.call('settings', 'get', 'settings/generate-contract-metadata')) return + const compiler = new CompilerAbstract(languageVersion, data, source) + var path = self._extractPathOf(source.target) + compiler.visitContracts((contract) => { + if (contract.file !== source.target) return + (async () => { + const fileName = self._JSONFileName(path, contract.name) + const content = await this.call('fileManager', 'exists', fileName) ? await this.call('fileManager', 'readFile', fileName) : null + await this._setArtefacts(content, contract, path) + })() + }) + }) + } + + _extractPathOf (file) { + var reg = /(.*)(\/).*/ + var path = reg.exec(file) + return path ? path[1] : '/' + } + + async _setArtefacts (content, contract, path) { + content = content || '{}' + var metadata + try { + metadata = JSON.parse(content) + } catch (e) { + console.log(e) + } + var fileName = this._JSONFileName(path, contract.name) + var metadataFileName = this._MetadataFileName(path, contract.name) + + var deploy = metadata.deploy || {} + this.networks.forEach((network) => { + deploy[network] = this._syncContext(contract, deploy[network] || {}) + }) + + let parsedMetadata + try { + parsedMetadata = JSON.parse(contract.object.metadata) + } catch (e) { + console.log(e) + } + if (parsedMetadata) await this.call('fileManager', 'writeFile', metadataFileName, JSON.stringify(parsedMetadata, null, '\t')) + + var data = { + deploy, + data: { + bytecode: contract.object.evm.bytecode, + deployedBytecode: contract.object.evm.deployedBytecode, + gasEstimates: contract.object.evm.gasEstimates, + methodIdentifiers: contract.object.evm.methodIdentifiers + }, + abi: contract.object.abi + } + await this.call('fileManager', 'writeFile', fileName, JSON.stringify(data, null, '\t')) + } + + _syncContext (contract, metadata) { + var linkReferences = metadata.linkReferences + var autoDeployLib = metadata.autoDeployLib + if (!linkReferences) linkReferences = {} + if (autoDeployLib === undefined) autoDeployLib = true + + for (var libFile in contract.object.evm.bytecode.linkReferences) { + if (!linkReferences[libFile]) linkReferences[libFile] = {} + for (var lib in contract.object.evm.bytecode.linkReferences[libFile]) { + if (!linkReferences[libFile][lib]) { + linkReferences[libFile][lib] = '
' + } + } + } + metadata.linkReferences = linkReferences + metadata.autoDeployLib = autoDeployLib + return metadata + } + + async deployMetadataOf (contractName, fileLocation) { + let path + if (fileLocation) { + path = fileLocation.split('/') + path.pop() + path = path.join('/') + } else { + try { + path = this._extractPathOf(await this.call('fileManager', 'getCurrentFile')) + } catch (err) { + console.log(err) + throw new Error(err) + } + } + try { + const { id, name } = await this.call('network', 'detectNetwork') + const fileName = this._JSONFileName(path, contractName) + try { + const content = await this.call('fileManager', 'readFile', fileName) + if (!content) return null + let metadata = JSON.parse(content) + metadata = metadata.deploy || {} + return metadata[name + ':' + id] || metadata[name] || metadata[id] || metadata[name.toLowerCase() + ':' + id] || metadata[name.toLowerCase()] + } catch (err) { + return null + } + } catch (err) { + console.log(err) + throw new Error(err) + } + } + + joinPath (...paths) { + paths = paths.filter((value) => value !== '').map((path) => path.replace(/^\/|\/$/g, '')) // remove first and last slash) + if (paths.length === 1) return paths[0] + return paths.join('/') + } +} diff --git a/libs/remix-core-plugin/src/lib/offset-line-to-column-converter.ts b/libs/remix-core-plugin/src/lib/offset-line-to-column-converter.ts new file mode 100644 index 0000000000..57c3f3ed2e --- /dev/null +++ b/libs/remix-core-plugin/src/lib/offset-line-to-column-converter.ts @@ -0,0 +1,77 @@ +'use strict' +import { Plugin } from '@remixproject/engine' + +import { sourceMappingDecoder } from '@remix-project/remix-debug' + +const profile = { + name: 'offsetToLineColumnConverter', + methods: ['offsetToLineColumn'], + events: [], + version: '0.0.1' +} + +export class OffsetToLineColumnConverter extends Plugin { + lineBreakPositionsByContent: {} + sourceMappingDecoder: any + constructor () { + super(profile) + this.lineBreakPositionsByContent = {} + this.sourceMappingDecoder = sourceMappingDecoder + } + + /** + * Convert offset representation with line/column representation. + * This is also used to resolve the content: + * @arg file is the index of the file in the content sources array and content sources array does have filename as key and not index. + * So we use the asts (which references both index and filename) to look up the actual content targeted by the @arg file index. + * @param {{start, length}} rawLocation - offset location + * @param {number} file - The index where to find the source in the sources parameters + * @param {Object.} sources - Map of content sources + * @param {Object.} asts - Map of content sources + */ + offsetToLineColumn (rawLocation, file, sources, asts) { + if (!this.lineBreakPositionsByContent[file]) { + const sourcesArray = Object.keys(sources) + if (!asts || (file === 0 && sourcesArray.length === 1)) { + // if we don't have ast, we process the only one available content (applicable also for compiler older than 0.4.12) + this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[sourcesArray[0]].content) + } else { + for (var filename in asts) { + const source = asts[filename] + if (source.id === file) { + this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[filename].content) + break + } + } + } + } + return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file]) + } + + /** + * Convert offset representation with line/column representation. + * @param {{start, length}} rawLocation - offset location + * @param {number} file - The index where to find the source in the sources parameters + * @param {string} content - source + */ + offsetToLineColumnWithContent (rawLocation, file, content) { + this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(content) + return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file]) + } + + /** + * Clear the cache + */ + clear () { + this.lineBreakPositionsByContent = {} + } + + /** + * called by plugin API + */ + activate () { + this.on('solidity', 'compilationFinished', () => { + this.clear() + }) + } +} diff --git a/libs/remix-core-plugin/tsconfig.json b/libs/remix-core-plugin/tsconfig.json new file mode 100644 index 0000000000..f14da61cdf --- /dev/null +++ b/libs/remix-core-plugin/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/libs/remix-core-plugin/tsconfig.lib.json b/libs/remix-core-plugin/tsconfig.lib.json new file mode 100644 index 0000000000..7e93feb2f8 --- /dev/null +++ b/libs/remix-core-plugin/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "outDir": "../../dist/out-tsc", + "declaration": true, + "rootDir": "./src", + "types": ["node"] + }, + "exclude": ["**/*.spec.ts"], + "include": ["**/*.ts"] +} diff --git a/libs/remix-debug/src/eventManager.ts b/libs/remix-debug/src/eventManager.ts index 60e83b0a78..f878395ed3 100644 --- a/libs/remix-debug/src/eventManager.ts +++ b/libs/remix-debug/src/eventManager.ts @@ -67,7 +67,7 @@ export class EventManager { } for (const listener in this.registered[eventName]) { const l = this.registered[eventName][listener] - l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) + if (l.func) l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) } } } diff --git a/libs/remix-debug/src/solidity-decoder/types/util.ts b/libs/remix-debug/src/solidity-decoder/types/util.ts index 30748c9aca..cd83d1cd32 100644 --- a/libs/remix-debug/src/solidity-decoder/types/util.ts +++ b/libs/remix-debug/src/solidity-decoder/types/util.ts @@ -48,7 +48,7 @@ export async function extractHexValue (location, storageResolver, byteLength) { try { slotvalue = await readFromStorage(location.slot, storageResolver) } catch (e) { - return '0x' + return '' } return extractHexByteSlice(slotvalue, byteLength, location.offset) } diff --git a/libs/remix-debug/src/trace/traceManager.ts b/libs/remix-debug/src/trace/traceManager.ts index 848b3c57aa..f4bf488392 100644 --- a/libs/remix-debug/src/trace/traceManager.ts +++ b/libs/remix-debug/src/trace/traceManager.ts @@ -151,7 +151,7 @@ export class TraceManager { if (this.trace[stepIndex] && this.trace[stepIndex].stack) { // there's always a stack const stack = this.trace[stepIndex].stack.slice(0) stack.reverse() - return stack + return stack.map(el => el.startsWith('0x') ? el : '0x' + el) } else { throw new Error('no stack found') } diff --git a/libs/remix-lib/src/eventManager.ts b/libs/remix-lib/src/eventManager.ts index 80280e8b27..a67548f899 100644 --- a/libs/remix-lib/src/eventManager.ts +++ b/libs/remix-lib/src/eventManager.ts @@ -64,7 +64,7 @@ export class EventManager { } for (const listener in this.registered[eventName]) { const l = this.registered[eventName][listener] - l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) + if (l.func) l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) } } } diff --git a/libs/remix-lib/src/init.ts b/libs/remix-lib/src/init.ts index 7e3d371715..43c68ee58f 100644 --- a/libs/remix-lib/src/init.ts +++ b/libs/remix-lib/src/init.ts @@ -12,23 +12,6 @@ export function extendWeb3 (web3) { this.extend(web3) } -export function setProvider (web3, url) { - web3.setProvider(new web3.providers.HttpProvider(url)) -} - -export function web3DebugNode (network) { - const web3DebugNodes = { - Main: 'https://gethmainnet.komputing.org', - Rinkeby: 'https://remix-rinkeby.ethdevops.io', - Ropsten: 'https://remix-ropsten.ethdevops.io', - Goerli: 'https://remix-goerli.ethdevops.io' - } - if (web3DebugNodes[network]) { - return this.loadWeb3(web3DebugNodes[network]) - } - return null -} - export function extend (web3) { if (!web3.extend) { return diff --git a/libs/remix-solidity/src/compiler/compiler-abstract.ts b/libs/remix-solidity/src/compiler/compiler-abstract.ts new file mode 100644 index 0000000000..81cd33db28 --- /dev/null +++ b/libs/remix-solidity/src/compiler/compiler-abstract.ts @@ -0,0 +1,48 @@ +'use strict' +import txHelper from './txHelper' + +export class CompilerAbstract { + languageversion: any + data: any + source: any + constructor (languageversion, data, source) { + this.languageversion = languageversion + this.data = data + this.source = source // source code + } + + getContracts () { + return this.data.contracts + } + + getContract (name) { + return txHelper.getContract(name, this.data.contracts) + } + + visitContracts (calllback) { + return txHelper.visitContracts(this.data.contracts, calllback) + } + + getData () { + return this.data + } + + getAsts () { + return this.data.sources // ast + } + + getSourceName (fileIndex) { + if (this.data && this.data.sources) { + return Object.keys(this.data.sources)[fileIndex] + } else if (Object.keys(this.source.sources).length === 1) { + // if we don't have ast, we return the only one filename present. + const sourcesArray = Object.keys(this.source.sources) + return sourcesArray[0] + } + return null + } + + getSourceCode () { + return this.source + } +} diff --git a/apps/remix-ide/src/app/compiler/compiler-helpers.js b/libs/remix-solidity/src/compiler/compiler-helpers.ts similarity index 89% rename from apps/remix-ide/src/app/compiler/compiler-helpers.js rename to libs/remix-solidity/src/compiler/compiler-helpers.ts index db7d5988f3..8a70e6be4f 100644 --- a/apps/remix-ide/src/app/compiler/compiler-helpers.js +++ b/libs/remix-solidity/src/compiler/compiler-helpers.ts @@ -1,7 +1,7 @@ 'use strict' import { canUseWorker, urlFromVersion } from './compiler-utils' -import { Compiler } from '@remix-project/remix-solidity' -import CompilerAbstract from './compiler-abstract' +import { CompilerAbstract } from './compiler-abstract' +import { Compiler } from './compiler' export const compile = async (compilationTargets, settings, contentResolverCallback) => { const res = await (() => { diff --git a/apps/remix-ide/src/app/compiler/compiler-utils.js b/libs/remix-solidity/src/compiler/compiler-utils.ts similarity index 100% rename from apps/remix-ide/src/app/compiler/compiler-utils.js rename to libs/remix-solidity/src/compiler/compiler-utils.ts diff --git a/libs/remix-solidity/src/index.ts b/libs/remix-solidity/src/index.ts index cb204a8af6..db63062910 100644 --- a/libs/remix-solidity/src/index.ts +++ b/libs/remix-solidity/src/index.ts @@ -1,3 +1,6 @@ export { Compiler } from './compiler/compiler' +export { compile } from './compiler/compiler-helpers' export { default as CompilerInput } from './compiler/compiler-input' +export { CompilerAbstract } from './compiler/compiler-abstract' export * from './compiler/types' +export * from './compiler/compiler-utils' diff --git a/libs/remix-solidity/src/lib/eventManager.ts b/libs/remix-solidity/src/lib/eventManager.ts index 289b2ec4eb..8282e09b6c 100644 --- a/libs/remix-solidity/src/lib/eventManager.ts +++ b/libs/remix-solidity/src/lib/eventManager.ts @@ -62,7 +62,7 @@ export default class EventManager { } for (const listener in this.registered[eventName]) { const l = this.registered[eventName][listener] - l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) + if (l.func) l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) } } } diff --git a/libs/remix-url-resolver/src/resolve.ts b/libs/remix-url-resolver/src/resolve.ts index 13029cefbd..38076686a2 100644 --- a/libs/remix-url-resolver/src/resolve.ts +++ b/libs/remix-url-resolver/src/resolve.ts @@ -30,6 +30,10 @@ export class RemixURLResolver { constructor (gistToken?: string, protocol = 'http:') { this.previouslyHandled = {} + this.setGistToken(gistToken, protocol) + } + + async setGistToken (gistToken?: string, protocol = 'http:') { this.gistAccessToken = gistToken || '' this.protocol = protocol } @@ -109,7 +113,7 @@ export class RemixURLResolver { url = url.replace(/^ipfs:\/\/?/, 'ipfs/') // eslint-disable-next-line no-useless-catch try { - const req = 'https://ipfsgw.komputing.org/' + url + const req = 'https://ipfs.remixproject.org/' + url // If you don't find greeter.sol on ipfs gateway use local // const req = 'http://localhost:8080/' + url const response: AxiosResponse = await axios.get(req) diff --git a/libs/remixd/src/origins.json b/libs/remixd/src/origins.json index d91e2f8a61..5a3331f3c7 100644 --- a/libs/remixd/src/origins.json +++ b/libs/remixd/src/origins.json @@ -6,6 +6,7 @@ "https://remix.ethereum.org", "package://a7df6d3c223593f3550b35e90d7b0b1f.mod", "package://6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod", - "https://ipfsgw.komputing.org" + "https://ipfsgw.komputing.org", + "https://ipfs.remixproject.org" ] } \ No newline at end of file diff --git a/nx.json b/nx.json index c46cb5df38..f2361ed2b7 100644 --- a/nx.json +++ b/nx.json @@ -105,7 +105,10 @@ "remix-ui-checkbox": { "tags": [] }, - "remix-ui-terminal": { +"remix-ui-terminal": { + }, + "remix-core-plugin": { + "tags": [] } } } diff --git a/package-lock.json b/package-lock.json index 2de36d2f31..d6fbf6186d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17562,12 +17562,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", @@ -21935,6 +21929,12 @@ "which": "^2.0.2" }, "dependencies": { + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", diff --git a/package.json b/package.json index 868b32492d..5e7eea6586 100644 --- a/package.json +++ b/package.json @@ -41,8 +41,8 @@ "workspace-schematic": "nx workspace-schematic", "dep-graph": "nx dep-graph", "help": "nx help", - "lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings", - "build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd", + "lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin", + "build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-core-plugin", "test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd", "publish:libs": "npm run build:libs && lerna publish --skip-git && npm run bumpVersion:libs", "build:e2e": "tsc -p apps/remix-ide-e2e/tsconfig.e2e.json", diff --git a/tsconfig.json b/tsconfig.json index 3e7b20eceb..10b05cc383 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -39,10 +39,13 @@ "@remix-ui/toaster": ["libs/remix-ui/toaster/src/index.ts"], "@remix-ui/file-explorer": ["libs/remix-ui/file-explorer/src/index.ts"], "@remix-ui/workspace": ["libs/remix-ui/workspace/src/index.ts"], - "@remix-ui/settings": ["libs/remix-ui/settings/src/index.ts"], "@remix-ui/static-analyser": ["libs/remix-ui/static-analyser/src/index.ts"], "@remix-ui/checkbox": ["libs/remix-ui/checkbox/src/index.ts"], - "@remix-ui/terminal": ["libs/remix-ui/terminal/src/index.ts"] + "@remix-ui/terminal": ["libs/remix-ui/terminal/src/index.ts"], + "@remix-ui/settings": ["libs/remix-ui/settings/src/index.ts"], + "@remix-project/core-plugin": [ + "libs/remix-core-plugin/src/index.ts" + ] } }, "exclude": ["node_modules", "tmp"] diff --git a/workspace.json b/workspace.json index 72dbe2fe82..33cd7bba22 100644 --- a/workspace.json +++ b/workspace.json @@ -811,6 +811,36 @@ } } } + }, + "remix-core-plugin": { + "root": "libs/remix-core-plugin", + "sourceRoot": "libs/remix-core-plugin/src", + "projectType": "library", + "schematics": {}, + "architect": { + "lint": { + "builder": "@nrwl/linter:lint", + "options": { + "linter": "eslint", + "tsConfig": [ + "libs/remix-core-plugin/tsconfig.lib.json" + ], + "exclude": [ + "**/node_modules/**", + "!libs/remix-core-plugin/**/*" + ] + } + }, + "build": { + "builder": "@nrwl/node:package", + "options": { + "outputPath": "dist/libs/core-plugin", + "tsConfig": "libs/remix-core-plugin/tsconfig.lib.json", + "packageJson": "libs/remix-core-plugin/package.json", + "main": "libs/remix-core-plugin/src/index.ts" + } + } + } } }, "cli": {