From 7bab2e0d76bc34ff010ebfa82b368b242816a6f8 Mon Sep 17 00:00:00 2001 From: filip mertens Date: Mon, 28 Jun 2021 17:02:23 +0200 Subject: [PATCH] plugin compilerMetadata --- apps/remix-ide/src/app.js | 5 +- .../src/app/files/compiler-metadata.js | 148 ------------------ apps/remix-ide/src/app/tabs/settings-tab.js | 6 +- .../src/lib/compiler-content-imports.ts | 2 +- .../compiler-metadata/.eslintrc | 1 + .../compiler-metadata/README.md | 3 + .../compiler-metadata/package.json | 11 ++ .../compiler-metadata/src/index.ts | 1 + .../src/lib/compiler-metadata.ts | 146 +++++++++++++++++ .../compiler-metadata/tsconfig.json | 10 ++ .../compiler-metadata/tsconfig.lib.json | 12 ++ nx.json | 3 + tsconfig.json | 3 + workspace.json | 31 +++- 14 files changed, 227 insertions(+), 155 deletions(-) delete mode 100644 apps/remix-ide/src/app/files/compiler-metadata.js create mode 100644 libs/remix-core-plugin/compiler-metadata/.eslintrc create mode 100644 libs/remix-core-plugin/compiler-metadata/README.md create mode 100644 libs/remix-core-plugin/compiler-metadata/package.json create mode 100644 libs/remix-core-plugin/compiler-metadata/src/index.ts create mode 100644 libs/remix-core-plugin/compiler-metadata/src/lib/compiler-metadata.ts create mode 100644 libs/remix-core-plugin/compiler-metadata/tsconfig.json create mode 100644 libs/remix-core-plugin/compiler-metadata/tsconfig.lib.json diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 3f855b5f02..039d0a9c15 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -21,6 +21,7 @@ import { CompilerArtefacts } from '@remix-core-plugin/compiler-artefacts' import { CompilerImports } from '@remix-core-plugin/compiler-content-imports' import { FetchAndCompile } from '@remix-core-plugin/compiler-fetch-and-compile' import { OffsetToLineColumnConverter } from '@remix-core-plugin/offset-line-to-column-converter' +import { CompilerMetadata } from '@remix-core-plugin/compiler-metadata' import migrateFileSystem from './migrateFileSystem' @@ -42,7 +43,7 @@ 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 Blockchain = require('./blockchain/blockchain.js') @@ -269,7 +270,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org 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 CompilerArtefacts() // store all the compilation results (key represent a compiler name) registry.put({ api: compilersArtefacts, name: 'compilersartefacts' }) 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 5c10ad1c7e..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' -import { CompilerAbstract } from '@remix-project/remix-solidity' - -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/tabs/settings-tab.js b/apps/remix-ide/src/app/tabs/settings-tab.js index b692fb2611..3d8da2b8a2 100644 --- a/apps/remix-ide/src/app/tabs/settings-tab.js +++ b/apps/remix-ide/src/app/tabs/settings-tab.js @@ -11,7 +11,7 @@ const _paq = window._paq = window._paq || [] const profile = { name: 'settings', displayName: 'Settings', - methods: ['getGithubAccessToken'], + methods: ['get'], events: [], icon: 'assets/img/settings.webp', description: 'Remix-IDE settings', @@ -257,8 +257,8 @@ module.exports = class SettingsTab extends ViewPlugin { return this._view.el } - getGithubAccessToken () { - return this.config.get('settings/gist-access-token') + get (key) { + return this.config.get(key) } updateMatomoAnalyticsChoice (isChecked) { diff --git a/libs/remix-core-plugin/compiler-content-imports/src/lib/compiler-content-imports.ts b/libs/remix-core-plugin/compiler-content-imports/src/lib/compiler-content-imports.ts index 85450a04d9..0e9e4ab8e0 100644 --- a/libs/remix-core-plugin/compiler-content-imports/src/lib/compiler-content-imports.ts +++ b/libs/remix-core-plugin/compiler-content-imports/src/lib/compiler-content-imports.ts @@ -24,7 +24,7 @@ export class CompilerImports extends Plugin { async setToken () { const protocol = typeof window !== 'undefined' && window.location.protocol - const token = await this.call('settings', 'getGithubAccessToken') + const token = await this.call('settings', 'get', 'settings/gist-access-token') this.urlResolver.setGistToken(token, protocol) } diff --git a/libs/remix-core-plugin/compiler-metadata/.eslintrc b/libs/remix-core-plugin/compiler-metadata/.eslintrc new file mode 100644 index 0000000000..1655d72922 --- /dev/null +++ b/libs/remix-core-plugin/compiler-metadata/.eslintrc @@ -0,0 +1 @@ +{ "extends": "../../../.eslintrc", "rules": {}, "ignorePatterns": ["!**/*"] } diff --git a/libs/remix-core-plugin/compiler-metadata/README.md b/libs/remix-core-plugin/compiler-metadata/README.md new file mode 100644 index 0000000000..96888a605b --- /dev/null +++ b/libs/remix-core-plugin/compiler-metadata/README.md @@ -0,0 +1,3 @@ +# remix-core-plugin-compiler-metadata + +This library was generated with [Nx](https://nx.dev). diff --git a/libs/remix-core-plugin/compiler-metadata/package.json b/libs/remix-core-plugin/compiler-metadata/package.json new file mode 100644 index 0000000000..f8a22f5ab6 --- /dev/null +++ b/libs/remix-core-plugin/compiler-metadata/package.json @@ -0,0 +1,11 @@ +{ + "name": "@remix-core-plugin/compiler-metadata", + "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" +} diff --git a/libs/remix-core-plugin/compiler-metadata/src/index.ts b/libs/remix-core-plugin/compiler-metadata/src/index.ts new file mode 100644 index 0000000000..2b81c60e16 --- /dev/null +++ b/libs/remix-core-plugin/compiler-metadata/src/index.ts @@ -0,0 +1 @@ +export * from './lib/compiler-metadata' diff --git a/libs/remix-core-plugin/compiler-metadata/src/lib/compiler-metadata.ts b/libs/remix-core-plugin/compiler-metadata/src/lib/compiler-metadata.ts new file mode 100644 index 0000000000..1991cfd2ae --- /dev/null +++ b/libs/remix-core-plugin/compiler-metadata/src/lib/compiler-metadata.ts @@ -0,0 +1,146 @@ +'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) { + console.log(err) + throw new Error(err) + } + } 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/compiler-metadata/tsconfig.json b/libs/remix-core-plugin/compiler-metadata/tsconfig.json new file mode 100644 index 0000000000..42882af48a --- /dev/null +++ b/libs/remix-core-plugin/compiler-metadata/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/libs/remix-core-plugin/compiler-metadata/tsconfig.lib.json b/libs/remix-core-plugin/compiler-metadata/tsconfig.lib.json new file mode 100644 index 0000000000..9c463b51e2 --- /dev/null +++ b/libs/remix-core-plugin/compiler-metadata/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/nx.json b/nx.json index dcfee1205d..3549933180 100644 --- a/nx.json +++ b/nx.json @@ -114,6 +114,9 @@ }, "offset-line-to-column-converter": { "tags": [] + }, + "compiler-metadata": { + "tags": [] } } } diff --git a/tsconfig.json b/tsconfig.json index 88cef54a3f..bf1134b50c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -52,6 +52,9 @@ ], "@remix-core-plugin/offset-line-to-column-converter": [ "libs/remix-core-plugin/offset-line-to-column-converter/src/index.ts" + ], + "@remix-core-plugin/compiler-metadata": [ + "libs/remix-core-plugin/compiler-metadata/src/index.ts" ] } }, diff --git a/workspace.json b/workspace.json index 0f6a4698fe..c01f8cd138 100644 --- a/workspace.json +++ b/workspace.json @@ -840,7 +840,6 @@ ] } }, - "build": { "builder": "@nrwl/node:package", "options": { @@ -881,6 +880,36 @@ } } } + }, + "compiler-metadata": { + "root": "libs/remix-core-plugin/compiler-metadata", + "sourceRoot": "libs/remix-core-plugin/compiler-metadata/src", + "projectType": "library", + "schematics": {}, + "architect": { + "lint": { + "builder": "@nrwl/linter:lint", + "options": { + "linter": "eslint", + "tsConfig": [ + "libs/remix-core-plugin/compiler-metadata/tsconfig.lib.json" + ], + "exclude": [ + "**/node_modules/**", + "!libs/remix-core-plugin/compiler-metadata/**/*" + ] + } + }, + "build": { + "builder": "@nrwl/node:package", + "options": { + "outputPath": "dist/libs/core-plugin/compiler-metadata", + "tsConfig": "libs/remix-core-plugin/compiler-metadata/tsconfig.lib.json", + "packageJson": "libs/remix-core-plugin/compiler-metadata/package.json", + "main": "libs/remix-core-plugin/compiler-metadata/src/index.ts" + } + } + } } }, "cli": {