diff --git a/.circleci/config.yml b/.circleci/config.yml index 005e4cfe6b..3458eb6302 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ parameters: type: boolean default: false orbs: - browser-tools: circleci/browser-tools@1.4.1 + browser-tools: circleci/browser-tools@1.4.4 win: circleci/windows@5.0 jobs: build: @@ -286,8 +286,9 @@ jobs: - browser-tools/install-browser-tools: install-firefox: false install-chrome: true + install-chromedriver: false install-geckodriver: false - install-chromedriver: true + - install-chromedriver-custom-linux - run: google-chrome --version - run: chromedriver --version - run: rm LICENSE.chromedriver 2> /dev/null || true @@ -310,6 +311,11 @@ jobs: - run: ls -la ./dist/apps/remix-ide/assets/js - run: yarn run selenium-install || yarn run selenium-install + - when: + condition: + equal: [ "chrome", << parameters.browser >> ] + steps: + - run: cp ~/bin/chromedriver /home/circleci/remix-project/node_modules/selenium-standalone/.selenium/chromedriver/latest-x64/ - run: name: Start Selenium command: yarn run selenium @@ -344,7 +350,8 @@ jobs: install-firefox: false install-chrome: true install-geckodriver: false - install-chromedriver: true + install-chromedriver: false + - install-chromedriver-custom-linux - run: google-chrome --version - run: chromedriver --version - run: rm LICENSE.chromedriver 2> /dev/null || true @@ -355,6 +362,7 @@ jobs: - run: unzip ./persist/plugin-<< parameters.plugin >>.zip - run: yarn install --cwd ./apps/remix-ide-e2e --modules-folder ../../node_modules - run: yarn run selenium-install || yarn run selenium-install + - run: cp ~/bin/chromedriver /home/circleci/remix-project/node_modules/selenium-standalone/.selenium/chromedriver/latest-x64/ - run: name: Start Selenium command: yarn run selenium @@ -522,3 +530,35 @@ workflows: only: remix_beta # VS Code Extension Version: 1.5.1 +commands: + install-chromedriver-custom-linux: + description: Custom script to install chromedriver with better version support for linux + steps: + - run: + name: install-chromedriver-custom-linux + command: | + google-chrome --version > version.txt + VERSION=$(grep -Eo '[0-9]+\.' < version.txt | head -1) + # CHROMEDRIVER_URL=$(curl -s 'https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json' | jq '.channels.Stable.downloads.chromedriver[] | select(.platform == "linux64") | .url' | tr -d '"') + CHROMEDRIVER_URL=$(curl -s 'https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json' | jq --arg v "$VERSION" '.versions[] | select(.version | startswith($v)) | .downloads.chromedriver[] | select(.platform == "linux64") | .url' | tail -n1 | tr -d '"') + echo $CHROMEDRIVER_URL + ZIPFILEPATH="/tmp/chromedriver.zip" + echo "Downloading from $CHROMEDRIVER_URL" + curl -f --silent $CHROMEDRIVER_URL > "$ZIPFILEPATH" + + BINFILEPATH="$HOME/bin/chromedriver-linux" + echo "Extracting to $BINFILEPATH" + unzip -p "$ZIPFILEPATH" chromedriver-linux64/chromedriver > "$BINFILEPATH" + + echo Setting execute flag + chmod +x "$BINFILEPATH" + + echo Updating symlink + ln -nfs "$BINFILEPATH" ~/bin/chromedriver + + echo Removing ZIP file + rm "$ZIPFILEPATH" + rm version.txt + + echo Done + chromedriver -v diff --git a/.eslintrc.json b/.eslintrc.json index e5f063f969..f4ba083cb7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -47,7 +47,13 @@ "eslint-disable-next-line no-empty": "off", "no-empty": "off", "jsx-a11y/anchor-is-valid": "off", - "@typescript-eslint/no-inferrable-types": "off" + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "react-hooks/exhaustive-deps": "off", + "array-callback-return": "off", + "prefer-spread": "off", + "indent": ["error", 2] } }, { @@ -58,10 +64,12 @@ "extends": [ "plugin:@nrwl/nx/javascript" ], - "rules": {} + "rules": { + "indent": ["error", 2] + } } ], "globals": { "JSX": true } -} \ No newline at end of file +} diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000000..618c2bfbc7 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + + diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..e9c70767c5 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,13 @@ +**/.yarn/* + +# Ignore node_modules +./node_modules + +# Ignore e2e files +./apps/remix-ide-e2e/* + +# Ignore build artefacts +./dist + +# Ignore all json files +**/*.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000000..5ab8667137 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "tabWidth": 2, + "useTabs": false, + "printWidth": 180, + "semi": false, + "singleQuote": true +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 841935f703..be04f3359d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -93,3 +93,21 @@ But in some cases, the `id` prop may not be static. For example, ``` You can't be sure there is a match key in locale file or not. So it will be better to provide a `defaultMessage` prop. + +### Should I update the non-english locale json files? +You probably will have this question when you are updating the english locale json files. + +Well, that depends. + +If you update an old json file, then you don't need to update it in other languages, because crowdin will do it for you. + +But if you add a new json file, then you have to add it in other languages, and import it in `index.js` of all languages. Because crowdin will not update `index.js`, you have to do it manually. + +### How to contribute on translations? +Remix is using crowdin to manage translations. If you want to contribute on that, you can do it on crowdin. Check the link below. + +https://crowdin.com/project/remix-translation + +There are many languages, just get into your language, and you will see a folder named `Remix UI`, where you can do the translations. + +Not only can you do the translations, you can also review it. If you agree or disagree with some translations, you can vote yes or no. If you vote no, you can comment to explain why you vote no, and give your translation. diff --git a/README.md b/README.md index 89f393cd6c..00ebb8c51d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ [![GitHub contributors](https://img.shields.io/github/contributors/ethereum/remix-project?style=flat&logo=github)](https://github.com/ethereum/remix-project/blob/master/CONTRIBUTING.md) [![Awesome Remix](https://img.shields.io/badge/Awesome--Remix-resources-green?logo=awesomelists)](https://github.com/ethereum/awesome-remix) ![GitHub](https://img.shields.io/github/license/ethereum/remix-project) -[![Gitter Chat](https://img.shields.io/badge/Gitter%20-chat-brightgreen?style=plastic&logo=gitter)](https://gitter.im/ethereum/remix) +[![Discord](https://img.shields.io/badge/join-discord-brightgreen.svg?style=flat&logo=discord)](https://discord.gg/q4vS2GVn) [![Twitter Follow](https://img.shields.io/twitter/follow/ethereumremix?style=flat&logo=twitter&color=green)](https://twitter.com/ethereumremix) @@ -63,14 +63,13 @@ yarn global add nx ```bash git clone https://github.com/ethereum/remix-project.git ``` -* Build `remix-project`: -```bash -cd remix-project -yarn install -yarn run build:libs // Build remix libs -nx build -nx serve -``` +* Build and Run `remix-project`: + +1. Move to project directory: `cd remix-project` +2. Install dependencies: `yarn install` or simply run `yarn` +3. Build Remix libraries: `yarn run build:libs` +4. Build Remix project: `yarn build` +5. Build and run project server: `yarn serve`. Optionally, run `yarn serve:hot` to enable hot module reload for frontend updates. Open `http://127.0.0.1:8080` in your browser to load Remix IDE locally. @@ -151,7 +150,7 @@ To run the Selenium tests via Nightwatch: - Install Selenium for the first time: `yarn run selenium-install` - Run a selenium server: `yarn run selenium` - - Build & Serve Remix: `nx serve` + - Build & Serve Remix: `yarn serve` - Run all the end-to-end tests: for Firefox: `yarn run nightwatch_local_firefox`, or @@ -283,7 +282,9 @@ parameters: ## Important Links +- Official website: https://remix-project.org - Official documentation: https://remix-ide.readthedocs.io/en/latest/ -- Curated list of Remix resources, tutorials etc.: https://github.com/ethereum/awesome-remix +- Curated list of Remix resources: https://github.com/ethereum/awesome-remix - Medium: https://medium.com/remix-ide - Twitter: https://twitter.com/ethereumremix +- Join Discord: https://discord.gg/q4vS2GVn diff --git a/apps/circuit-compiler/project.json b/apps/circuit-compiler/project.json new file mode 100644 index 0000000000..eb501cc21d --- /dev/null +++ b/apps/circuit-compiler/project.json @@ -0,0 +1,59 @@ +{ + "name": "circuit-compiler", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/circuit-compiler/src", + "projectType": "application", + "implicitDependencies": ["remixd"], + "targets": { + "build": { + "executor": "@nrwl/webpack:webpack", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "development", + "options": { + "compiler": "babel", + "outputPath": "dist/apps/circuit-compiler", + "index": "apps/circuit-compiler/src/index.html", + "baseHref": "./", + "main": "apps/circuit-compiler/src/main.tsx", + "polyfills": "apps/circuit-compiler/src/polyfills.ts", + "tsConfig": "apps/circuit-compiler/tsconfig.app.json", + "assets": ["apps/circuit-compiler/src/profile.json"], + "styles": ["apps/circuit-compiler/src/css/app.css"], + "scripts": [], + "webpackConfig": "apps/circuit-compiler/webpack.config.js" + }, + "configurations": { + "development": { + }, + "production": { + "fileReplacements": [ + { + "replace": "apps/circuit-compiler/src/environments/environment.ts", + "with": "apps/circuit-compiler/src/environments/environment.prod.ts" + } + ] + } + } + }, + "serve": { + "executor": "@nrwl/webpack:dev-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "circuit-compiler:build", + "hmr": true, + "baseHref": "/" + }, + "configurations": { + "development": { + "buildTarget": "circuit-compiler:build:development", + "port": 2023 + }, + "production": { + "buildTarget": "circuit-compiler:build:production" + } + } + } + }, + "tags": [] + } + \ No newline at end of file diff --git a/apps/circuit-compiler/src/app/app.tsx b/apps/circuit-compiler/src/app/app.tsx new file mode 100644 index 0000000000..e922fb0bf9 --- /dev/null +++ b/apps/circuit-compiler/src/app/app.tsx @@ -0,0 +1,17 @@ +import React, { useEffect } from 'react' + +import { CircomPluginClient } from './services/circomPluginClient' + +function App() { + + useEffect(() => { + new CircomPluginClient() + }, []) + + return ( +
+
+ ) +} + +export default App \ No newline at end of file diff --git a/apps/circuit-compiler/src/app/services/circomPluginClient.ts b/apps/circuit-compiler/src/app/services/circomPluginClient.ts new file mode 100644 index 0000000000..f94b1317f4 --- /dev/null +++ b/apps/circuit-compiler/src/app/services/circomPluginClient.ts @@ -0,0 +1,224 @@ +import {PluginClient} from '@remixproject/plugin' +import {createClient} from '@remixproject/plugin-webview' +import EventManager from 'events' +import pathModule from 'path' +import {parse} from 'circom_wasm' + +export class CircomPluginClient extends PluginClient { + public internalEvents: EventManager + + constructor() { + super() + createClient(this) + this.internalEvents = new EventManager() + this.methods = ['init', 'parse'] + this.onload() + } + + init(): void { + console.log('initializing circom plugin...') + } + + onActivation(): void { + // @ts-ignore + this.on('editor', 'contentChanged', (path: string, fileContent) => { + if (path.endsWith('.circom')) { + this.parse(path, fileContent) + } + }) + } + + async parse(path: string, fileContent: string): Promise { + let buildFiles = { + [path]: fileContent + } + + buildFiles = await this.resolveDependencies(path, fileContent, buildFiles) + const parsedOutput = parse(path, buildFiles) + + try { + const result = JSON.parse(parsedOutput) + + if (result.length === 0) { + // @ts-ignore + await this.call('editor', 'clearErrorMarkers', [path]) + } else { + const markers = [] + + for (const report of result) { + for (const label in report.labels) { + if (report.labels[label].file_id === '0') { + // @ts-ignore + const startPosition: {lineNumber: number; column: number} = + await this.call( + 'editor', + // @ts-ignore + 'getPositionAt', + report.labels[label].range.start + ) + // @ts-ignore + const endPosition: {lineNumber: number; column: number} = + await this.call( + 'editor', + // @ts-ignore + 'getPositionAt', + report.labels[label].range.end + ) + + markers.push({ + message: report.message, + severity: report.type.toLowerCase(), + position: { + start: { + line: startPosition.lineNumber, + column: startPosition.column + }, + end: { + line: endPosition.lineNumber, + column: endPosition.column + } + }, + file: path + }) + } + } + } + + if (markers.length > 0) { + // @ts-ignore + await this.call('editor', 'addErrorMarker', markers) + } else { + // @ts-ignore + await this.call('editor', 'clearErrorMarkers', [path]) + } + } + } catch (e) { + console.log(e) + } + } + + async resolveDependencies( + filePath: string, + fileContent: string, + output = {}, + depPath: string = '', + blackPath: string[] = [] + ): Promise> { + // extract all includes + const includes = (fileContent.match(/include ['"].*['"]/g) || []).map( + (include) => include.replace(/include ['"]/g, '').replace(/['"]/g, '') + ) + + await Promise.all( + includes.map(async (include) => { + // fix for endless recursive includes + if (blackPath.includes(include)) return + let dependencyContent = '' + let path = include + // @ts-ignore + const pathExists = await this.call('fileManager', 'exists', path) + + if (pathExists) { + // fetch file content if include import (path) exists within same level as current file opened in editor + dependencyContent = await this.call('fileManager', 'readFile', path) + } else { + // if include import (path) does not exist, try to construct relative path using the original file path (current file opened in editor) + let relativePath = pathModule.resolve( + filePath.slice(0, filePath.lastIndexOf('/')), + include + ) + if (relativePath.indexOf('/') === 0) + relativePath = relativePath.slice(1) + const relativePathExists = await this.call( + 'fileManager', + // @ts-ignore + 'exists', + relativePath + ) + + if (relativePathExists) { + // fetch file content if include import exists as a relative path + dependencyContent = await this.call( + 'fileManager', + 'readFile', + relativePath + ) + } else { + if (depPath) { + // if depPath is provided, try to resolve include import from './deps' folder in remix + path = pathModule.resolve( + depPath.slice(0, depPath.lastIndexOf('/')), + include + ) + if (path.indexOf('/') === 0) path = path.slice(1) + dependencyContent = await this.call( + 'contentImport', + 'resolveAndSave', + path, + null + ) + } else { + if (include.startsWith('circomlib')) { + // try to resolve include import from github if it is a circomlib dependency + const splitInclude = include.split('/') + const version = splitInclude[1].match(/v[0-9]+.[0-9]+.[0-9]+/g) + + if (version && version[0]) { + path = `https://raw.githubusercontent.com/iden3/circomlib/${ + version[0] + }/circuits/${splitInclude.slice(2).join('/')}` + dependencyContent = await this.call( + 'contentImport', + 'resolveAndSave', + path, + null + ) + } else { + path = `https://raw.githubusercontent.com/iden3/circomlib/master/circuits/${splitInclude + .slice(1) + .join('/')}` + dependencyContent = await this.call( + 'contentImport', + 'resolveAndSave', + path, + null + ) + } + } else { + // If all import cases are not true, use the default import to try fetching from node_modules and unpkg + dependencyContent = await this.call( + 'contentImport', + 'resolveAndSave', + path, + null + ) + } + } + } + } + // extract all includes from the dependency content + const dependencyIncludes = ( + dependencyContent.match(/include ['"].*['"]/g) || [] + ).map((include) => + include.replace(/include ['"]/g, '').replace(/['"]/g, '') + ) + + blackPath.push(include) + // recursively resolve all dependencies of the dependency + if (dependencyIncludes.length > 0) { + await this.resolveDependencies( + filePath, + dependencyContent, + output, + path, + blackPath + ) + output[include] = dependencyContent + } else { + output[include] = dependencyContent + } + }) + ) + return output + } +} diff --git a/apps/circuit-compiler/src/css/app.css b/apps/circuit-compiler/src/css/app.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/circuit-compiler/src/example/simple.circom b/apps/circuit-compiler/src/example/simple.circom new file mode 100644 index 0000000000..9a2120df7a --- /dev/null +++ b/apps/circuit-compiler/src/example/simple.circom @@ -0,0 +1,11 @@ +pragma circom 2.0.0; + +template Multiplier2() { + signal input a; + signal input b; + signal output c; + c <== a*b; + } + + component main = Multiplier2(); + \ No newline at end of file diff --git a/apps/circuit-compiler/src/index.html b/apps/circuit-compiler/src/index.html new file mode 100644 index 0000000000..adb93d90f1 --- /dev/null +++ b/apps/circuit-compiler/src/index.html @@ -0,0 +1,15 @@ + + + + + Circuit - Compiler + + + + + + + +
+ + diff --git a/apps/circuit-compiler/src/main.tsx b/apps/circuit-compiler/src/main.tsx new file mode 100644 index 0000000000..b63438d846 --- /dev/null +++ b/apps/circuit-compiler/src/main.tsx @@ -0,0 +1,8 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import App from './app/app' + +ReactDOM.render( + , + document.getElementById('root') +) \ No newline at end of file diff --git a/apps/circuit-compiler/src/polyfills.ts b/apps/circuit-compiler/src/polyfills.ts new file mode 100644 index 0000000000..2adf3d05b6 --- /dev/null +++ b/apps/circuit-compiler/src/polyfills.ts @@ -0,0 +1,7 @@ +/** + * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. + * + * See: https://github.com/zloirock/core-js#babel + */ +import 'core-js/stable'; +import 'regenerator-runtime/runtime'; diff --git a/apps/circuit-compiler/src/profile.json b/apps/circuit-compiler/src/profile.json new file mode 100644 index 0000000000..e8395e2574 --- /dev/null +++ b/apps/circuit-compiler/src/profile.json @@ -0,0 +1,17 @@ +{ + "name": "circuit-compiler", + "kind": "provider", + "displayName": "Circuit Compiler", + "events": [], + "version": "2.0.0", + "methods": ["init", "parse"], + "canActivate": [], + "url": "", + "description": "Enables circuit compilation and computing a witness for ZK proofs", + "icon": "https://docs.circom.io/assets/images/favicon.png", + "location": "hiddenPanel", + "documentation": "", + "repo": "https://github.com/ethereum/remix-project/tree/master/apps/circuit-compiler", + "maintainedBy": "Remix", + "authorContact": "" +} diff --git a/apps/circuit-compiler/tsconfig.app.json b/apps/circuit-compiler/tsconfig.app.json new file mode 100644 index 0000000000..2272b8a388 --- /dev/null +++ b/apps/circuit-compiler/tsconfig.app.json @@ -0,0 +1,24 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "exclude": [ + "jest.config.ts", + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] + } + \ No newline at end of file diff --git a/apps/circuit-compiler/tsconfig.json b/apps/circuit-compiler/tsconfig.json new file mode 100644 index 0000000000..3b6130a0a8 --- /dev/null +++ b/apps/circuit-compiler/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + } + ] + } + \ No newline at end of file diff --git a/apps/circuit-compiler/webpack.config.js b/apps/circuit-compiler/webpack.config.js new file mode 100644 index 0000000000..fecff4fa70 --- /dev/null +++ b/apps/circuit-compiler/webpack.config.js @@ -0,0 +1,92 @@ +const { composePlugins, withNx } = require('@nrwl/webpack') +const webpack = require('webpack') +const TerserPlugin = require("terser-webpack-plugin") +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") + +// Nx plugins for webpack. +module.exports = composePlugins(withNx(), (config) => { + // Update the webpack config as needed here. + // e.g. `config.plugins.push(new MyPlugin())` + // add fallback for node modules + config.resolve.fallback = { + ...config.resolve.fallback, + "crypto": require.resolve("crypto-browserify"), + "stream": require.resolve("stream-browserify"), + "path": require.resolve("path-browserify"), + "http": require.resolve("stream-http"), + "https": require.resolve("https-browserify"), + "constants": require.resolve("constants-browserify"), + "os": false, //require.resolve("os-browserify/browser"), + "timers": false, // require.resolve("timers-browserify"), + "zlib": require.resolve("browserify-zlib"), + "fs": false, + "module": false, + "tls": false, + "net": false, + "readline": false, + "child_process": false, + "buffer": require.resolve("buffer/"), + "vm": require.resolve('vm-browserify'), + } + + + // add externals + config.externals = { + ...config.externals, + solc: 'solc', + } + + // add public path + config.output.publicPath = './' + + // add copy & provide plugin + config.plugins.push( + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + url: ['url', 'URL'], + process: 'process/browser', + }) + ) + + // set the define plugin to load the WALLET_CONNECT_PROJECT_ID + config.plugins.push( + new webpack.DefinePlugin({ + WALLET_CONNECT_PROJECT_ID: JSON.stringify(process.env.WALLET_CONNECT_PROJECT_ID), + }) + ) + + // souce-map loader + config.module.rules.push({ + test: /\.js$/, + use: ["source-map-loader"], + enforce: "pre" + }) + + config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings + + + // set minimizer + config.optimization.minimizer = [ + new TerserPlugin({ + parallel: true, + terserOptions: { + ecma: 2015, + compress: false, + mangle: false, + format: { + comments: false, + }, + }, + extractComments: false, + }), + new CssMinimizerPlugin(), + ]; + + config.watchOptions = { + ignored: /node_modules/ + } + + config.experiments.syncWebAssembly = true + + return config; +}); diff --git a/apps/debugger/src/app/app.tsx b/apps/debugger/src/app/app.tsx index 5cee11a2d9..f6e07dc685 100644 --- a/apps/debugger/src/app/app.tsx +++ b/apps/debugger/src/app/app.tsx @@ -1,17 +1,17 @@ -import React, { useState, useEffect } from 'react'; +import React, {useState, useEffect} from 'react' -import { DebuggerUI } from '@remix-ui/debugger-ui' // eslint-disable-line +import {DebuggerUI} from '@remix-ui/debugger-ui' // eslint-disable-line -import { DebuggerClientApi } from './debugger' +import {DebuggerClientApi} from './debugger' const remix = new DebuggerClientApi() -export const App = () => { +export const App = () => { return (
- ); -}; + ) +} -export default App; +export default App diff --git a/apps/debugger/src/app/debugger.ts b/apps/debugger/src/app/debugger.ts index 28e9703470..008402467d 100644 --- a/apps/debugger/src/app/debugger.ts +++ b/apps/debugger/src/app/debugger.ts @@ -27,5 +27,4 @@ export class DebuggerClientApi extends DebuggerApiMixin(PluginClient) { web3: () => any // returns an instance of web3.js onStartDebugging: (debuggerBackend: any) => void // called when debug starts onStopDebugging: () => void // called when debug stops -} - +} \ No newline at end of file diff --git a/apps/debugger/src/main.tsx b/apps/debugger/src/main.tsx index bc1579ec0f..be9ae3d572 100644 --- a/apps/debugger/src/main.tsx +++ b/apps/debugger/src/main.tsx @@ -1,9 +1,6 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; +import React from 'react' +import ReactDOM from 'react-dom' -import App from './app/app'; +import App from './app/app' -ReactDOM.render( - , - document.getElementById('root') -); +ReactDOM.render(, document.getElementById('root')) diff --git a/apps/debugger/webpack.config.js b/apps/debugger/webpack.config.js index 9feb0dc08d..4bc648f1db 100644 --- a/apps/debugger/webpack.config.js +++ b/apps/debugger/webpack.config.js @@ -1,8 +1,7 @@ -const { composePlugins, withNx } = require('@nrwl/webpack') +const {composePlugins, withNx} = require('@nrwl/webpack') const webpack = require('webpack') -const TerserPlugin = require("terser-webpack-plugin") -const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") - +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') // Nx plugins for webpack. module.exports = composePlugins(withNx(), (config) => { @@ -12,56 +11,52 @@ module.exports = composePlugins(withNx(), (config) => { // add fallback for node modules config.resolve.fallback = { ...config.resolve.fallback, - "crypto": require.resolve("crypto-browserify"), - "stream": require.resolve("stream-browserify"), - "path": require.resolve("path-browserify"), - "http": require.resolve("stream-http"), - "https": require.resolve("https-browserify"), - "constants": require.resolve("constants-browserify"), - "os": false, //require.resolve("os-browserify/browser"), - "timers": false, // require.resolve("timers-browserify"), - "zlib": require.resolve("browserify-zlib"), - "fs": false, - "module": false, - "tls": false, - "net": false, - "readline": false, - "child_process": false, - "buffer": require.resolve("buffer/"), - "vm": require.resolve('vm-browserify'), + crypto: require.resolve('crypto-browserify'), + stream: require.resolve('stream-browserify'), + path: require.resolve('path-browserify'), + http: require.resolve('stream-http'), + https: require.resolve('https-browserify'), + constants: require.resolve('constants-browserify'), + os: false, //require.resolve("os-browserify/browser"), + timers: false, // require.resolve("timers-browserify"), + zlib: require.resolve('browserify-zlib'), + fs: false, + module: false, + tls: false, + net: false, + readline: false, + child_process: false, + buffer: require.resolve('buffer/'), + vm: require.resolve('vm-browserify') } - // add externals config.externals = { ...config.externals, - solc: 'solc', + solc: 'solc' } // add public path config.output.publicPath = '/' - - // add copy & provide plugin config.plugins.push( new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], url: ['url', 'URL'], - process: 'process/browser', + process: 'process/browser' }) ) // souce-map loader config.module.rules.push({ test: /\.js$/, - use: ["source-map-loader"], - enforce: "pre" + use: ['source-map-loader'], + enforce: 'pre' }) config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings - // set minimizer config.optimization.minimizer = [ new TerserPlugin({ @@ -71,17 +66,17 @@ module.exports = composePlugins(withNx(), (config) => { compress: false, mangle: false, format: { - comments: false, - }, + comments: false + } }, - extractComments: false, + extractComments: false }), - new CssMinimizerPlugin(), - ]; + new CssMinimizerPlugin() + ] config.watchOptions = { ignored: /node_modules/ } - return config; -}); + return config +}) diff --git a/apps/doc-gen/src/app/App.tsx b/apps/doc-gen/src/app/App.tsx index a11b5b99e8..08fe6f7ba2 100644 --- a/apps/doc-gen/src/app/App.tsx +++ b/apps/doc-gen/src/app/App.tsx @@ -4,13 +4,13 @@ import './App.css' import { DocGenClient } from './docgen-client' import { Build } from './docgen/site' -export const client = new DocGenClient() +export const client = new DocGenClient() const App = () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [themeType, setThemeType] = useState('dark'); - const [hasBuild, setHasBuild] = useState(false); - const [fileName, setFileName] = useState(''); + const [themeType, setThemeType] = useState('dark') + const [hasBuild, setHasBuild] = useState(false) + const [fileName, setFileName] = useState('') useEffect(() => { const watchThemeSwitch = async () => { @@ -21,19 +21,27 @@ const App = () => { setHasBuild(true) setFileName(fileName) }) - client.eventEmitter.on('docsGenerated', (docs: string[]) => { - }) + client.eventEmitter.on('docsGenerated', (docs: string[]) => {}) } watchThemeSwitch() }, []) return (
-
Compile a Solidity contract and generate its documentation as Markdown. (Right-click on a contract in the File Explorer and select "Generate Docs" from the context menu.).
- {fileName &&
-
File: {fileName}
-
} - {hasBuild && } +
+ Compile a Solidity contract and generate its documentation as Markdown. (Right-click on a contract in the File + Explorer and select "Generate Docs" from the context menu.). +
+ {fileName && ( +
+
File: {fileName}
+
+ )} + {hasBuild && ( + + )}
) } diff --git a/apps/doc-gen/src/app/hooks/useLocalStorage.tsx b/apps/doc-gen/src/app/hooks/useLocalStorage.tsx index d677de7813..955658bac5 100644 --- a/apps/doc-gen/src/app/hooks/useLocalStorage.tsx +++ b/apps/doc-gen/src/app/hooks/useLocalStorage.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState } from 'react' export function useLocalStorage(key: string, initialValue: any) { // State to store our value @@ -6,32 +6,31 @@ export function useLocalStorage(key: string, initialValue: any) { const [storedValue, setStoredValue] = useState(() => { try { // Get from local storage by key - const item = window.localStorage.getItem(key); + const item = window.localStorage.getItem(key) // Parse stored json or if none return initialValue - return item ? JSON.parse(item) : initialValue; + return item ? JSON.parse(item) : initialValue } catch (error) { // If error also return initialValue - console.log(error); - return initialValue; + console.log(error) + return initialValue } - }); + }) // Return a wrapped version of useState's setter function that ... // ... persists the new value to localStorage. const setValue = (value: any) => { try { // Allow value to be a function so we have same API as useState - const valueToStore = - value instanceof Function ? value(storedValue) : value; + const valueToStore = value instanceof Function ? value(storedValue) : value // Save state - setStoredValue(valueToStore); + setStoredValue(valueToStore) // Save to local storage - window.localStorage.setItem(key, JSON.stringify(valueToStore)); + window.localStorage.setItem(key, JSON.stringify(valueToStore)) } catch (error) { // A more advanced implementation would handle the error case - console.log(error); + console.log(error) } - }; + } - return [storedValue, setValue]; + return [storedValue, setValue] } diff --git a/apps/doc-gen/src/app/views/ErrorView.tsx b/apps/doc-gen/src/app/views/ErrorView.tsx index f1c4fdaf91..31a3b90a73 100644 --- a/apps/doc-gen/src/app/views/ErrorView.tsx +++ b/apps/doc-gen/src/app/views/ErrorView.tsx @@ -1,31 +1,28 @@ -import React from "react"; +import React from 'react' export const ErrorView: React.FC = () => { return (
Error page
Sorry, something unexpected happened.
- Please raise an issue:{" "} - + Please raise an issue:{' '} + Here
- ); -}; + ) +} diff --git a/apps/doc-gen/src/main.tsx b/apps/doc-gen/src/main.tsx index a6dc3b3a47..d2d29f2bb4 100644 --- a/apps/doc-gen/src/main.tsx +++ b/apps/doc-gen/src/main.tsx @@ -1,11 +1,11 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import App from "./app/App"; +import React from 'react' +import ReactDOM from 'react-dom' +import App from './app/App' // import { Routes } from "./routes"; ReactDOM.render( , - document.getElementById("root") -); + document.getElementById('root'), +) diff --git a/apps/doc-gen/webpack.config.js b/apps/doc-gen/webpack.config.js index b7f8e45da0..86bcf51395 100644 --- a/apps/doc-gen/webpack.config.js +++ b/apps/doc-gen/webpack.config.js @@ -1,19 +1,19 @@ const { composePlugins, withNx } = require('@nrwl/webpack') const { withReact } = require('@nrwl/react') const webpack = require('webpack') -const TerserPlugin = require("terser-webpack-plugin") -const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') // Nx plugins for webpack. -module.exports = composePlugins(withNx(), withReact(), (config) => { +module.exports = composePlugins(withNx(), withReact(), config => { // Update the webpack config as needed here. // e.g. `config.plugins.push(new MyPlugin())` // add fallback for node modules config.resolve.fallback = { ...config.resolve.fallback, - "path": require.resolve("path-browserify"), - "fs": false, + path: require.resolve('path-browserify'), + fs: false, } // add externals @@ -24,10 +24,9 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { config.module.rules.push({ test: /\.hbs$/, - type: 'asset/source' + type: 'asset/source', }) - // add public path config.output.publicPath = '/' @@ -38,16 +37,14 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { url: ['url', 'URL'], process: 'process/browser', }), - new webpack.DefinePlugin({ - - }), + new webpack.DefinePlugin({}), ) // souce-map loader config.module.rules.push({ test: /\.js$/, - use: ["source-map-loader"], - enforce: "pre" + use: ['source-map-loader'], + enforce: 'pre', }) config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings @@ -67,7 +64,7 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { extractComments: false, }), new CssMinimizerPlugin(), - ]; + ] - return config; + return config }) diff --git a/apps/doc-viewer/src/app/App.tsx b/apps/doc-viewer/src/app/App.tsx index cbb57460d0..5f5092eb24 100644 --- a/apps/doc-viewer/src/app/App.tsx +++ b/apps/doc-viewer/src/app/App.tsx @@ -1,5 +1,5 @@ -import React, { useEffect, useState } from "react" -import { DocViewer } from "./docviewer" +import React, {useEffect, useState} from 'react' +import {DocViewer} from './docviewer' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' @@ -11,13 +11,12 @@ export default function App() { client.eventEmitter.on('contentsReady', (fileContents: string) => { setContents(fileContents) }) - }, []) return ( <>
- +
) -} \ No newline at end of file +} diff --git a/apps/doc-viewer/src/main.tsx b/apps/doc-viewer/src/main.tsx index 7b8dd49ee6..b8ec0b96a0 100644 --- a/apps/doc-viewer/src/main.tsx +++ b/apps/doc-viewer/src/main.tsx @@ -6,5 +6,5 @@ ReactDOM.render( , - document.getElementById("root") -); + document.getElementById('root') +) diff --git a/apps/doc-viewer/webpack.config.js b/apps/doc-viewer/webpack.config.js index 1a460e3da0..b21898ae87 100644 --- a/apps/doc-viewer/webpack.config.js +++ b/apps/doc-viewer/webpack.config.js @@ -1,8 +1,8 @@ -const { composePlugins, withNx } = require('@nrwl/webpack') -const { withReact } = require('@nrwl/react') +const {composePlugins, withNx} = require('@nrwl/webpack') +const {withReact} = require('@nrwl/react') const webpack = require('webpack') -const TerserPlugin = require("terser-webpack-plugin") -const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') // Nx plugins for webpack. module.exports = composePlugins(withNx(), withReact(), (config) => { @@ -12,7 +12,7 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { // add externals config.externals = { ...config.externals, - solc: 'solc', + solc: 'solc' } // add public path @@ -23,18 +23,16 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], url: ['url', 'URL'], - process: 'process/browser', - }), - new webpack.DefinePlugin({ - + process: 'process/browser' }), + new webpack.DefinePlugin({}) ) // souce-map loader config.module.rules.push({ test: /\.js$/, - use: ["source-map-loader"], - enforce: "pre" + use: ['source-map-loader'], + enforce: 'pre' }) config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings @@ -48,13 +46,13 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { compress: false, mangle: false, format: { - comments: false, - }, + comments: false + } }, - extractComments: false, + extractComments: false }), - new CssMinimizerPlugin(), - ]; + new CssMinimizerPlugin() + ] - return config; + return config }) diff --git a/apps/etherscan/src/app/AppContext.tsx b/apps/etherscan/src/app/AppContext.tsx index 52b0c1fda8..f121406a67 100644 --- a/apps/etherscan/src/app/AppContext.tsx +++ b/apps/etherscan/src/app/AppContext.tsx @@ -1,24 +1,24 @@ -import React from "react" -import { PluginClient } from "@remixproject/plugin" +import React from 'react' +import {PluginClient} from '@remixproject/plugin' -import { Receipt, ThemeType } from "./types" +import {Receipt, ThemeType} from './types' export const AppContext = React.createContext({ - apiKey: "", + apiKey: '', setAPIKey: (value: string) => { - console.log("Set API Key from Context") + console.log('Set API Key from Context') }, clientInstance: {} as PluginClient, receipts: [] as Receipt[], setReceipts: (receipts: Receipt[]) => { - console.log("Calling Set Receipts") + console.log('Calling Set Receipts') }, contracts: [] as string[], setContracts: (contracts: string[]) => { - console.log("Calling Set Contract Names") + console.log('Calling Set Contract Names') }, - themeType: "dark" as ThemeType, + themeType: 'dark' as ThemeType, setThemeType: (themeType: ThemeType) => { - console.log("Calling Set Theme Type") - }, + console.log('Calling Set Theme Type') + } }) diff --git a/apps/etherscan/src/app/RemixPlugin.tsx b/apps/etherscan/src/app/RemixPlugin.tsx index 979f2c967d..59967c5e41 100644 --- a/apps/etherscan/src/app/RemixPlugin.tsx +++ b/apps/etherscan/src/app/RemixPlugin.tsx @@ -1,40 +1,59 @@ -import { PluginClient } from '@remixproject/plugin'; -import { verify, EtherScanReturn } from './utils/verify'; -import { getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus } from './utils'; +import {PluginClient} from '@remixproject/plugin' +import {verify, EtherScanReturn} from './utils/verify' +import {getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus} from './utils' export class RemixClient extends PluginClient { + loaded() { + return this.onload() + } - loaded() { - return this.onload() - } - - async verify (apiKey: string, contractAddress: string, contractArguments: string, contractName: string, compilationResultParam: any, chainRef?: number | string, isProxyContract?: boolean, expectedImplAddress?: string) { - const result = await verify(apiKey, contractAddress, contractArguments, contractName, compilationResultParam, chainRef, isProxyContract, expectedImplAddress, this, - (value: EtherScanReturn) => {}, (value: string) => {}) - return result - } + async verify( + apiKey: string, + contractAddress: string, + contractArguments: string, + contractName: string, + compilationResultParam: any, + chainRef?: number | string, + isProxyContract?: boolean, + expectedImplAddress?: string + ) { + const result = await verify( + apiKey, + contractAddress, + contractArguments, + contractName, + compilationResultParam, + chainRef, + isProxyContract, + expectedImplAddress, + this, + (value: EtherScanReturn) => {}, + (value: string) => {} + ) + return result + } + + async receiptStatus(receiptGuid: string, apiKey: string, isProxyContract: boolean) { + try { + const {network, networkId} = await getNetworkName(this) + if (network === 'vm') { + throw new Error('Cannot check the receipt status in the selected network') + } + const etherscanApi = getEtherScanApi(networkId) + let receiptStatus - async receiptStatus (receiptGuid: string, apiKey: string, isProxyContract: boolean) { - try { - const { network, networkId } = await getNetworkName(this) - if (network === "vm") { - throw new Error("Cannot check the receipt status in the selected network") - } - const etherscanApi = getEtherScanApi(networkId) - let receiptStatus - - if (isProxyContract) receiptStatus = await getProxyContractReceiptStatus(receiptGuid, apiKey, etherscanApi) - else receiptStatus = await getReceiptStatus(receiptGuid, apiKey, etherscanApi) - return { - message: receiptStatus.result, - succeed: receiptStatus.status === '0' ? false : true - } - } catch (e: any){ - return { - status: 'error', - message: e.message, - succeed: false - } - } + if (isProxyContract) receiptStatus = await getProxyContractReceiptStatus(receiptGuid, apiKey, etherscanApi) + else receiptStatus = await getReceiptStatus(receiptGuid, apiKey, etherscanApi) + return { + message: receiptStatus.result, + succeed: receiptStatus.status === '0' ? false : true + } + } catch (e: any) { + return { + status: 'error', + message: e.message, + succeed: false + } } + } } diff --git a/apps/etherscan/src/app/app.tsx b/apps/etherscan/src/app/app.tsx index 501e3620ae..972413f7f2 100644 --- a/apps/etherscan/src/app/app.tsx +++ b/apps/etherscan/src/app/app.tsx @@ -1,22 +1,19 @@ -import React, { useState, useEffect, useRef } from "react" +import React, {useState, useEffect, useRef} from 'react' -import { - CompilationFileSources, - CompilationResult, -} from "@remixproject/plugin-api" +import {CompilationFileSources, CompilationResult} from '@remixproject/plugin-api' -import { RemixClient } from "./RemixPlugin"; -import { createClient } from "@remixproject/plugin-webview"; +import {RemixClient} from './RemixPlugin' +import {createClient} from '@remixproject/plugin-webview' -import { AppContext } from "./AppContext" -import { DisplayRoutes } from "./routes" +import {AppContext} from './AppContext' +import {DisplayRoutes} from './routes' -import { useLocalStorage } from "./hooks/useLocalStorage" +import {useLocalStorage} from './hooks/useLocalStorage' -import { getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus } from "./utils" -import { Receipt, ThemeType } from "./types" +import {getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus} from './utils' +import {Receipt, ThemeType} from './types' -import "./App.css" +import './App.css' export const getNewContractNames = (compilationResult: CompilationResult) => { const compiledContracts = compilationResult.contracts @@ -31,11 +28,11 @@ export const getNewContractNames = (compilationResult: CompilationResult) => { } const App = () => { - const [apiKey, setAPIKey] = useLocalStorage("apiKey", "") + const [apiKey, setAPIKey] = useLocalStorage('apiKey', '') const [clientInstance, setClientInstance] = useState(undefined as any) - const [receipts, setReceipts] = useLocalStorage("receipts", []) + const [receipts, setReceipts] = useLocalStorage('receipts', []) const [contracts, setContracts] = useState([] as string[]) - const [themeType, setThemeType] = useState("dark" as ThemeType) + const [themeType, setThemeType] = useState('dark' as ThemeType) const timer = useRef(null) const clientInstanceRef = useRef(clientInstance) @@ -49,26 +46,15 @@ const App = () => { const loadClient = async () => { await client.onload() setClientInstance(client) - client.on("solidity", - "compilationFinished", - ( - fileName: string, - source: CompilationFileSources, - languageVersion: string, - data: CompilationResult - ) => { - const newContractsNames = getNewContractNames(data) - - const newContractsToSave: string[] = [ - ...contractsRef.current, - ...newContractsNames, - ] - - const uniqueContracts: string[] = [...new Set(newContractsToSave)] - - setContracts(uniqueContracts) - } - ) + client.on('solidity', 'compilationFinished', (fileName: string, source: CompilationFileSources, languageVersion: string, data: CompilationResult) => { + const newContractsNames = getNewContractNames(data) + + const newContractsToSave: string[] = [...contractsRef.current, ...newContractsNames] + + const uniqueContracts: string[] = [...new Set(newContractsToSave)] + + setContracts(uniqueContracts) + }) //const currentTheme = await client.call("theme", "currentTheme") //setThemeType(currentTheme.quality) @@ -82,7 +68,7 @@ const App = () => { useEffect(() => { let receiptsNotVerified: Receipt[] = receipts.filter((item: Receipt) => { - return item.status === "Pending in queue" || item.status === "Max rate limit reached" + return item.status === 'Pending in queue' || item.status === 'Max rate limit reached' }) if (receiptsNotVerified.length > 0) { @@ -91,51 +77,41 @@ const App = () => { timer.current = null } timer.current = setInterval(async () => { - const { network, networkId } = await getNetworkName(clientInstanceRef.current) + const {network, networkId} = await getNetworkName(clientInstanceRef.current) if (!clientInstanceRef.current) { return } - - if (network === "vm") { + + if (network === 'vm') { return } let newReceipts = receipts - for (const item of receiptsNotVerified) { - await new Promise(r => setTimeout(r, 500)) // avoid api rate limit exceed. + for (const item of receiptsNotVerified) { + await new Promise((r) => setTimeout(r, 500)) // avoid api rate limit exceed. let status if (item.isProxyContract) { - status = await getProxyContractReceiptStatus( - item.guid, - apiKey, - getEtherScanApi(networkId) - ) + status = await getProxyContractReceiptStatus(item.guid, apiKey, getEtherScanApi(networkId)) if (status.status === '1') { status.message = status.result status.result = 'Successfully Updated' } - } else - status = await getReceiptStatus( - item.guid, - apiKey, - getEtherScanApi(networkId) - ) - if (status.result === "Pass - Verified" || status.result === "Already Verified" || - status.result === "Successfully Updated") { + } else status = await getReceiptStatus(item.guid, apiKey, getEtherScanApi(networkId)) + if (status.result === 'Pass - Verified' || status.result === 'Already Verified' || status.result === 'Successfully Updated') { newReceipts = newReceipts.map((currentReceipt: Receipt) => { if (currentReceipt.guid === item.guid) { - let res = { + const res = { ...currentReceipt, - status: status.result, + status: status.result } if (currentReceipt.isProxyContract) res.message = status.message return res } return currentReceipt - }) - } + }) + } } receiptsNotVerified = newReceipts.filter((item: Receipt) => { - return item.status === "Pending in queue" || item.status === "Max rate limit reached" + return item.status === 'Pending in queue' || item.status === 'Max rate limit reached' }) if (timer.current && receiptsNotVerified.length === 0) { clearInterval(timer.current) @@ -157,7 +133,7 @@ const App = () => { contracts, setContracts, themeType, - setThemeType, + setThemeType }} > @@ -165,4 +141,4 @@ const App = () => { ) } -export default App \ No newline at end of file +export default App diff --git a/apps/etherscan/src/app/components/HeaderWithSettings.tsx b/apps/etherscan/src/app/components/HeaderWithSettings.tsx index f8c0423c91..8f302dd596 100644 --- a/apps/etherscan/src/app/components/HeaderWithSettings.tsx +++ b/apps/etherscan/src/app/components/HeaderWithSettings.tsx @@ -1,8 +1,8 @@ -import React from "react" +import React from 'react' -import { NavLink } from "react-router-dom" -import { CustomTooltip } from '@remix-ui/helper' -import { AppContext } from "../AppContext" +import {NavLink} from 'react-router-dom' +import {CustomTooltip} from '@remix-ui/helper' +import {AppContext} from '../AppContext' interface Props { title?: string @@ -13,79 +13,67 @@ interface IconProps { from: string } -const HomeIcon: React.FC = ({ from }: IconProps) => { +const HomeIcon: React.FC = ({from}: IconProps) => { return ( isActive ? "btn p-0 m-0" : "btn text-dark p-0 m-0"} - state={ from } + className={({isActive}) => (isActive ? 'border border-secondary shadow-none btn p-1 m-0' : 'border-0 shadow-none btn p-1 m-0')} + style={({isActive}) => (!isActive ? {width: '1.8rem', filter: 'contrast(0.5)'} : {width: '1.8rem'})} + state={from} > - + ) } -const ReceiptsIcon: React.FC = ({ from }: IconProps) => { +const ReceiptsIcon: React.FC = ({from}: IconProps) => { return ( - isActive ? "btn p-0 m-0 mx-2" : "btn text-dark p-0 m-0 mx-2"} - state={ from } + className={({isActive}) => (isActive ? 'border border-secondary shadow-none btn p-1 m-0' : 'border-0 shadow-none btn p-1 m-0')} + style={({isActive}) => (!isActive ? {width: '1.8rem', filter: 'contrast(0.5)'} : {width: '1.8rem'})} + state={from} > - + ) } -const SettingsIcon: React.FC = ({ from }: IconProps) => { +const SettingsIcon: React.FC = ({from}: IconProps) => { return ( isActive ? "btn p-0 m-0" : "btn text-dark p-0 m-0"} - state= {from} + className={({isActive}) => (isActive ? 'border border-secondary shadow-none btn p-1 m-0' : 'border-0 shadow-none btn p-1 m-0')} + style={({isActive}) => (!isActive ? {width: '1.8rem', filter: 'contrast(0.5)'} : {width: '1.8rem'})} + state={from} > - + ) } -export const HeaderWithSettings: React.FC = ({ - title = "", - from, -}) => { +export const HeaderWithSettings: React.FC = ({title = '', from}) => { return ( {() => (
{title}
-
+
diff --git a/apps/etherscan/src/app/components/SubmitButton.tsx b/apps/etherscan/src/app/components/SubmitButton.tsx index 83a080ca6a..080fafc708 100644 --- a/apps/etherscan/src/app/components/SubmitButton.tsx +++ b/apps/etherscan/src/app/components/SubmitButton.tsx @@ -1,5 +1,5 @@ -import React from "react" -import { CustomTooltip } from '@remix-ui/helper' +import React from 'react' +import {CustomTooltip} from '@remix-ui/helper' interface Props { text: string @@ -8,35 +8,21 @@ interface Props { disable?: boolean } -export const SubmitButton: React.FC = ({ - text, - dataId, - isSubmitting = false, - disable = true -}) => { +export const SubmitButton: React.FC = ({text, dataId, isSubmitting = false, disable = true}) => { return (
- + +
+ +
) - } - } + }} ) } -const ReceiptsTable: React.FC<{ receipts: Receipt[] }> = ({ receipts }) => { +const ReceiptsTable: React.FC<{receipts: Receipt[]}> = ({receipts}) => { return (
Receipts
@@ -167,20 +146,23 @@ const ReceiptsTable: React.FC<{ receipts: Receipt[] }> = ({ receipts }) => { receipts.map((item: Receipt, index) => { return ( - - {item.status} - {item.status === 'Successfully Updated' && - - + + {item.status} + {item.status === 'Successfully Updated' && ( + + + + )} {item.guid} diff --git a/apps/etherscan/src/app/views/VerifyView.tsx b/apps/etherscan/src/app/views/VerifyView.tsx index 35f5fce803..adfd0e6cfb 100644 --- a/apps/etherscan/src/app/views/VerifyView.tsx +++ b/apps/etherscan/src/app/views/VerifyView.tsx @@ -1,16 +1,14 @@ -import React, { useEffect, useRef, useState } from "react" +import React, {useEffect, useRef, useState} from 'react' import Web3 from 'web3' -import { - PluginClient, -} from "@remixproject/plugin" -import { CustomTooltip } from '@remix-ui/helper' -import { Formik, ErrorMessage, Field } from "formik" +import {PluginClient} from '@remixproject/plugin' +import {CustomTooltip} from '@remix-ui/helper' +import {Formik, ErrorMessage, Field} from 'formik' -import { SubmitButton } from "../components" -import { Receipt } from "../types" -import { verify } from "../utils/verify" -import { etherscanScripts } from "@remix-project/remix-ws-templates" +import {SubmitButton} from '../components' +import {Receipt} from '../types' +import {verify} from '../utils/verify' +import {etherscanScripts} from '@remix-project/remix-ws-templates' interface Props { client: PluginClient @@ -25,15 +23,10 @@ interface FormValues { expectedImplAddress?: string } -export const VerifyView: React.FC = ({ - apiKey, - client, - contracts, - onVerifiedContract, -}) => { - const [results, setResults] = useState("") - const [networkName, setNetworkName] = useState("Loading...") - const [selectedContract, setSelectedContract] = useState("") +export const VerifyView: React.FC = ({apiKey, client, contracts, onVerifiedContract}) => { + const [results, setResults] = useState('') + const [networkName, setNetworkName] = useState('Loading...') + const [selectedContract, setSelectedContract] = useState('') const [showConstructorArgs, setShowConstructorArgs] = useState(false) const [isProxyContract, setIsProxyContract] = useState(false) const [constructorInputs, setConstructorInputs] = useState([]) @@ -41,13 +34,13 @@ export const VerifyView: React.FC = ({ useEffect(() => { if (client && client.on) { - client.on("blockchain" as any, 'networkStatus', (result) => { + client.on('blockchain' as any, 'networkStatus', (result) => { setNetworkName(`${result.network.name} ${result.network.id !== '-' ? `(Chain id: ${result.network.id})` : '(Not supported)'}`) }) } return () => { // To fix memory leak - if (client && client.off) client.off("blockchain" as any, 'networkStatus') + if (client && client.off) client.off('blockchain' as any, 'networkStatus') } }, [client]) @@ -56,8 +49,8 @@ export const VerifyView: React.FC = ({ }, [contracts]) const updateConsFields = (contractName) => { - client.call("compilerArtefacts" as any, "getArtefactsByContractName", contractName).then((result) => { - const { artefact } = result + client.call('compilerArtefacts' as any, 'getArtefactsByContractName', contractName).then((result) => { + const {artefact} = result if (artefact && artefact.abi && artefact.abi[0] && artefact.abi[0].type && artefact.abi[0].type === 'constructor' && artefact.abi[0].inputs.length > 0) { setConstructorInputs(artefact.abi[0].inputs) setShowConstructorArgs(true) @@ -69,13 +62,10 @@ export const VerifyView: React.FC = ({ } const onVerifyContract = async (values: FormValues) => { - const compilationResult = (await client.call( - "solidity", - "getCompilationResult" - )) as any + const compilationResult = (await client.call('solidity', 'getCompilationResult')) as any if (!compilationResult) { - throw new Error("no compilation result available") + throw new Error('no compilation result available') } const constructorValues = [] @@ -83,9 +73,9 @@ export const VerifyView: React.FC = ({ if (key.startsWith('contractArgValue')) constructorValues.push(values[key]) } const web3 = new Web3() - const constructorTypes = constructorInputs.map(e => e.type) - let contractArguments = web3.eth.abi.encodeParameters(constructorTypes, constructorValues) - contractArguments = contractArguments.replace("0x", "") + const constructorTypes = constructorInputs.map((e) => e.type) + let contractArguments = web3.eth.abi.encodeParameters(constructorTypes, constructorValues) + contractArguments = contractArguments.replace('0x', '') verificationResult.current = await verify( apiKey, @@ -98,7 +88,7 @@ export const VerifyView: React.FC = ({ values.expectedImplAddress, client, onVerifiedContract, - setResults, + setResults ) setResults(verificationResult.current['message']) } @@ -107,199 +97,148 @@ export const VerifyView: React.FC = ({
{ const errors = {} as any if (!values.contractName) { - errors.contractName = "Required" + errors.contractName = 'Required' } if (!values.contractAddress) { - errors.contractAddress = "Required" + errors.contractAddress = 'Required' } - if (values.contractAddress.trim() === "" || !values.contractAddress.startsWith('0x') - || values.contractAddress.length !== 42) { - errors.contractAddress = "Please enter a valid contract address" + if (values.contractAddress.trim() === '' || !values.contractAddress.startsWith('0x') || values.contractAddress.length !== 42) { + errors.contractAddress = 'Please enter a valid contract address' } return errors }} onSubmit={(values) => onVerifyContract(values)} > - {({ errors, touched, handleSubmit, handleChange, isSubmitting }) => { - return (
-
- - + {({errors, touched, handleSubmit, handleChange, isSubmitting}) => { + return ( + +
+ + + + +
+
+ - -
- -
- - { - handleChange(e) - setSelectedContract(e.target.value) - updateConsFields(e.target.value) - }} - > - - {contracts.map((item) => ( - - ))} - - -
- -
- + {contracts.map((item) => ( + + ))} + + +
+
+ {constructorInputs.map((item, index) => { return (
- - - + + +
- )} - )} - -
- -
- - - -
+ ) + })} +
+
+ { - handleChange(e) - if (e.target.checked) setIsProxyContract(true) - else setIsProxyContract(false) - }} - /> - -
-
- -
- - - - - - -
- - -
- -
+
+ + + + + + +
+ +
+ + - + ) - } - } + }}
-
- {/*
View Receipts
*/} diff --git a/apps/etherscan/src/main.tsx b/apps/etherscan/src/main.tsx index 353ad43f6d..5f17c9ab24 100644 --- a/apps/etherscan/src/main.tsx +++ b/apps/etherscan/src/main.tsx @@ -1,7 +1,11 @@ -import { StrictMode } from 'react'; -import * as ReactDOM from 'react-dom'; +import {StrictMode} from 'react' +import * as ReactDOM from 'react-dom' +import App from './app/app' -import App from './app/app'; - -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( + + + , + document.getElementById('root') +) diff --git a/apps/etherscan/webpack.config.js b/apps/etherscan/webpack.config.js index e28638e84e..5564f25b94 100644 --- a/apps/etherscan/webpack.config.js +++ b/apps/etherscan/webpack.config.js @@ -1,7 +1,7 @@ -const { composePlugins, withNx } = require('@nrwl/webpack') +const {composePlugins, withNx} = require('@nrwl/webpack') const webpack = require('webpack') -const TerserPlugin = require("terser-webpack-plugin") -const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') const versionData = { timestamp: Date.now(), @@ -15,29 +15,29 @@ module.exports = composePlugins(withNx(), (config) => { // add fallback for node modules config.resolve.fallback = { ...config.resolve.fallback, - "crypto": require.resolve("crypto-browserify"), - "stream": require.resolve("stream-browserify"), - "path": require.resolve("path-browserify"), - "http": require.resolve("stream-http"), - "https": require.resolve("https-browserify"), - "constants": require.resolve("constants-browserify"), - "os": false, //require.resolve("os-browserify/browser"), - "timers": false, // require.resolve("timers-browserify"), - "zlib": require.resolve("browserify-zlib"), - "fs": false, - "module": false, - "tls": false, - "net": false, - "readline": false, - "child_process": false, - "buffer": require.resolve("buffer/"), - "vm": require.resolve('vm-browserify'), + crypto: require.resolve('crypto-browserify'), + stream: require.resolve('stream-browserify'), + path: require.resolve('path-browserify'), + http: require.resolve('stream-http'), + https: require.resolve('https-browserify'), + constants: require.resolve('constants-browserify'), + os: false, //require.resolve("os-browserify/browser"), + timers: false, // require.resolve("timers-browserify"), + zlib: require.resolve('browserify-zlib'), + fs: false, + module: false, + tls: false, + net: false, + readline: false, + child_process: false, + buffer: require.resolve('buffer/'), + vm: require.resolve('vm-browserify') } // add externals config.externals = { ...config.externals, - solc: 'solc', + solc: 'solc' } // add public path @@ -47,26 +47,24 @@ module.exports = composePlugins(withNx(), (config) => { config.output.filename = `[name].plugin-etherscan.${versionData.timestamp}.js` config.output.chunkFilename = `[name].plugin-etherscan.${versionData.timestamp}.js` - // add copy & provide plugin config.plugins.push( new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], url: ['url', 'URL'], - process: 'process/browser', + process: 'process/browser' }) ) // souce-map loader config.module.rules.push({ test: /\.js$/, - use: ["source-map-loader"], - enforce: "pre" + use: ['source-map-loader'], + enforce: 'pre' }) config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings - // set minimizer config.optimization.minimizer = [ new TerserPlugin({ @@ -76,17 +74,17 @@ module.exports = composePlugins(withNx(), (config) => { compress: false, mangle: false, format: { - comments: false, - }, + comments: false + } }, - extractComments: false, + extractComments: false }), - new CssMinimizerPlugin(), - ]; + new CssMinimizerPlugin() + ] config.watchOptions = { ignored: /node_modules/ } - return config; -}); + return config +}) diff --git a/apps/remix-ide-e2e/nightwatch.ts b/apps/remix-ide-e2e/nightwatch.ts index 3f59c1549e..7e05269897 100644 --- a/apps/remix-ide-e2e/nightwatch.ts +++ b/apps/remix-ide-e2e/nightwatch.ts @@ -7,7 +7,7 @@ module.exports = { globals_path: '', test_settings: { - default: { + 'default': { selenium_port: 4444, selenium_host: 'localhost', globals: { @@ -23,28 +23,29 @@ module.exports = { exclude: ['dist/apps/remix-ide-e2e/src/tests/runAndDeploy.test.js', 'dist/apps/remix-ide-e2e/src/tests/pluginManager.test.ts'] }, - chrome: { + 'chrome': { desiredCapabilities: { - browserName: 'chrome', - javascriptEnabled: true, - acceptSslCerts: true, + 'browserName': 'chrome', + 'javascriptEnabled': true, + 'acceptSslCerts': true, 'goog:chromeOptions': { - args: ['window-size=2560,1440', - 'start-fullscreen', - '--no-sandbox', - '--headless', - '--verbose', - "--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36", + args: [ + 'window-size=2560,1440', + 'start-fullscreen', + '--no-sandbox', + '--headless', + '--verbose', + '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36' ] } } }, - chromeDesktop: { + 'chromeDesktop': { desiredCapabilities: { - browserName: 'chrome', - javascriptEnabled: true, - acceptSslCerts: true, + 'browserName': 'chrome', + 'javascriptEnabled': true, + 'acceptSslCerts': true, 'goog:chromeOptions': { args: ['window-size=2560,1440', 'start-fullscreen', '--no-sandbox'] } @@ -53,40 +54,33 @@ module.exports = { 'chrome-runAndDeploy': { desiredCapabilities: { - browserName: 'chrome', - javascriptEnabled: true, - acceptSslCerts: true, + 'browserName': 'chrome', + 'javascriptEnabled': true, + 'acceptSslCerts': true, 'goog:chromeOptions': { args: ['window-size=2560,1440', 'start-fullscreen', '--no-sandbox', '--headless', '--verbose'] } } }, - firefoxDesktop: { + 'firefoxDesktop': { desiredCapabilities: { - browserName: 'firefox', - javascriptEnabled: true, - acceptSslCerts: true, + 'browserName': 'firefox', + 'javascriptEnabled': true, + 'acceptSslCerts': true, 'moz:firefoxOptions': { - args: [ - '-width=2560', - '-height=1440' - ] + args: ['-width=2560', '-height=1440'] } } }, - firefox: { + 'firefox': { desiredCapabilities: { - browserName: 'firefox', - javascriptEnabled: true, - acceptSslCerts: true, + 'browserName': 'firefox', + 'javascriptEnabled': true, + 'acceptSslCerts': true, 'moz:firefoxOptions': { - args: [ - '-headless', - '-width=2560', - '-height=1440' - ] + args: ['-headless', '-width=2560', '-height=1440'] } } } diff --git a/apps/remix-ide-e2e/package.json b/apps/remix-ide-e2e/package.json index 7ea9249703..62a2588d35 100644 --- a/apps/remix-ide-e2e/package.json +++ b/apps/remix-ide-e2e/package.json @@ -6,14 +6,14 @@ "npm": "^6.14.15" }, "dependencies": { - "@openzeppelin/contracts": "^4.8.3", - "@openzeppelin/contracts-upgradeable": "^4.8.3", - "@openzeppelin/upgrades-core": "^1.22.0", - "@openzeppelin/wizard": "^0.1.1", + "@openzeppelin/contracts": "^5.0.0", + "@openzeppelin/contracts-upgradeable": "^5.0.0", + "@openzeppelin/upgrades-core": "^1.30.0", + "@openzeppelin/wizard": "^0.4.0", "@remix-project/remixd": "../../dist/libs/remixd", "deep-equal": "^1.0.1", "ganache-cli": "^6.8.1", - "selenium-standalone": "^8.2.3", + "selenium-standalone": "^9.0.3", "tree-kill": "^1.2.2" }, "devDependencies": { diff --git a/apps/remix-ide-e2e/src/commands/checkAnnotations.ts b/apps/remix-ide-e2e/src/commands/checkAnnotations.ts index e83a0c6ce1..e3f9805d55 100644 --- a/apps/remix-ide-e2e/src/commands/checkAnnotations.ts +++ b/apps/remix-ide-e2e/src/commands/checkAnnotations.ts @@ -1,9 +1,9 @@ import EventEmitter from 'events' -import { NightwatchBrowser } from 'nightwatch' +import {NightwatchBrowser} from 'nightwatch' class checkAnnotations extends EventEmitter { - command (this: NightwatchBrowser, type: string, line: number): NightwatchBrowser { - this.api.assert.containsText(`.margin-view-overlays .${type} + div`, line.toString()).perform(() => this.emit('complete')) + command(this: NightwatchBrowser, type: string): NightwatchBrowser { + this.api.waitForElementPresent(`.glyph-margin-widgets .${type}`).perform(() => this.emit('complete')) return this } } diff --git a/apps/remix-ide-e2e/src/commands/checkAnnotationsNotPresent.ts b/apps/remix-ide-e2e/src/commands/checkAnnotationsNotPresent.ts index 6ca51e102a..2fc96c890b 100644 --- a/apps/remix-ide-e2e/src/commands/checkAnnotationsNotPresent.ts +++ b/apps/remix-ide-e2e/src/commands/checkAnnotationsNotPresent.ts @@ -1,9 +1,9 @@ import EventEmitter from 'events' -import { NightwatchBrowser } from 'nightwatch' +import {NightwatchBrowser} from 'nightwatch' class checkAnnotationsNotPresent extends EventEmitter { - command (this: NightwatchBrowser, type: string): NightwatchBrowser { - this.api.waitForElementNotPresent(`.margin-view-overlays .${type}`).perform(() => this.emit('complete')) + command(this: NightwatchBrowser, type: string): NightwatchBrowser { + this.api.waitForElementNotPresent(`.glyph-margin-widgets .${type}`).perform(() => this.emit('complete')) return this } } diff --git a/apps/remix-ide-e2e/src/commands/clickFunction.ts b/apps/remix-ide-e2e/src/commands/clickFunction.ts index 9ae4b3c330..f437108892 100644 --- a/apps/remix-ide-e2e/src/commands/clickFunction.ts +++ b/apps/remix-ide-e2e/src/commands/clickFunction.ts @@ -1,20 +1,37 @@ -import { NightwatchBrowser, NightwatchClickFunctionExpectedInput } from 'nightwatch' +import { + NightwatchBrowser, + NightwatchClickFunctionExpectedInput +} from 'nightwatch' import EventEmitter from 'events' class ClickFunction extends EventEmitter { - command (this: NightwatchBrowser, fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser { - this.api.waitForElementPresent('.instance button[data-title="' + fnFullName + '"]') + command( + this: NightwatchBrowser, + fnFullName: string, + expectedInput?: NightwatchClickFunctionExpectedInput + ): NightwatchBrowser { + this.api + .waitForElementPresent('.instance *[data-title="' + fnFullName + '"]') .perform(function (client, done) { - client.execute(function () { - document.querySelector('#runTabView').scrollTop = document.querySelector('#runTabView').scrollHeight - }, [], function () { - if (expectedInput) { - client.setValue('#runTabView input[data-title="' + expectedInput.types + '"]', expectedInput.values, _ => _) + client.execute( + function () { + document.querySelector('#runTabView').scrollTop = + document.querySelector('#runTabView').scrollHeight + }, + [], + function () { + if (expectedInput) { + client.setValue( + '#runTabView input[data-title="' + expectedInput.types + '"]', + expectedInput.values, + (_) => _ + ) + } + done() } - done() - }) + ) }) - .scrollAndClick('.instance button[data-title="' + fnFullName + '"]') + .scrollAndClick('.instance *[data-title="' + fnFullName + '"]') .pause(2000) .perform(() => { this.emit('complete') diff --git a/apps/remix-ide-e2e/src/commands/createContract.ts b/apps/remix-ide-e2e/src/commands/createContract.ts index 015a4f2012..046f747c83 100644 --- a/apps/remix-ide-e2e/src/commands/createContract.ts +++ b/apps/remix-ide-e2e/src/commands/createContract.ts @@ -16,11 +16,11 @@ class CreateContract extends EventEmitter { function createContract (browser: NightwatchBrowser, inputParams: string, callback: VoidFunction) { if (inputParams) { browser.setValue('.udapp_contractActionsContainerSingle > input', inputParams, function () { - browser.click('.udapp_contractActionsContainerSingle > button').pause(500).perform(function () { callback() }) + browser.click('.udapp_contractActionsContainerSingle > div').pause(500).perform(function () { callback() }) }) } else { browser - .click('.udapp_contractActionsContainerSingle > button') + .click('.udapp_contractActionsContainerSingle > div') .pause(500) .perform(function () { callback() }) } diff --git a/apps/remix-ide-e2e/src/commands/testConstantFunction.ts b/apps/remix-ide-e2e/src/commands/testConstantFunction.ts index 3216bc39ed..6498f75283 100644 --- a/apps/remix-ide-e2e/src/commands/testConstantFunction.ts +++ b/apps/remix-ide-e2e/src/commands/testConstantFunction.ts @@ -1,36 +1,80 @@ -import { NightwatchBrowser, NightwatchTestConstantFunctionExpectedInput } from 'nightwatch' +import { + NightwatchBrowser, + NightwatchTestConstantFunctionExpectedInput +} from 'nightwatch' import EventEmitter from 'events' class TestConstantFunction extends EventEmitter { - command (this: NightwatchBrowser, address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser { + command( + this: NightwatchBrowser, + address: string, + fnFullName: string, + expectedInput: NightwatchTestConstantFunctionExpectedInput | null, + expectedOutput: string + ): NightwatchBrowser { console.log('TestConstantFunction ' + address + ' fnFullName') this.api.perform((done) => { - testConstantFunction(this.api, address, fnFullName, expectedInput, expectedOutput, () => { - done() - this.emit('complete') - }) + testConstantFunction( + this.api, + address, + fnFullName, + expectedInput, + expectedOutput, + () => { + done() + this.emit('complete') + } + ) }) return this } } -function testConstantFunction (browser: NightwatchBrowser, address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput, expectedOutput: string, cb: VoidFunction) { - browser.waitForElementPresent('.instance button[data-title="' + fnFullName + '"]').perform(function (client, done) { - client.execute(function () { - document.querySelector('#runTabView').scrollTop = document.querySelector('#runTabView').scrollHeight - }, [], function () { - if (expectedInput) { - client.waitForElementPresent('#runTabView input[data-title="' + expectedInput.types + '"]') - .setValue('#runTabView input[data-title="' + expectedInput.types + '"]', expectedInput.values) - } - done() +function testConstantFunction( + browser: NightwatchBrowser, + address: string, + fnFullName: string, + expectedInput: NightwatchTestConstantFunctionExpectedInput, + expectedOutput: string, + cb: VoidFunction +) { + browser + .waitForElementPresent('.instance *[data-title="' + fnFullName + '"]') + .perform(function (client, done) { + client.execute( + function () { + document.querySelector('#runTabView').scrollTop = + document.querySelector('#runTabView').scrollHeight + }, + [], + function () { + if (expectedInput) { + client + .waitForElementPresent( + '#runTabView input[data-title="' + expectedInput.types + '"]' + ) + .setValue( + '#runTabView input[data-title="' + expectedInput.types + '"]', + expectedInput.values + ) + } + done() + } + ) }) - }) - .click(`#instance${address} button[data-title="${fnFullName}"]`) + .click(`#instance${address} *[data-title="${fnFullName}"]`) .pause(1000) - .waitForElementPresent('#instance' + address + ' .udapp_contractActionsContainer .udapp_value') - .scrollInto('#instance' + address + ' .udapp_contractActionsContainer .udapp_value') - .assert.containsText('#instance' + address + ' .udapp_contractActionsContainer', expectedOutput).perform(() => { + .waitForElementPresent( + '#instance' + address + ' .udapp_contractActionsContainer .udapp_value' + ) + .scrollInto( + '#instance' + address + ' .udapp_contractActionsContainer .udapp_value' + ) + .assert.containsText( + '#instance' + address + ' .udapp_contractActionsContainer', + expectedOutput + ) + .perform(() => { cb() }) } diff --git a/apps/remix-ide-e2e/src/local-plugin/src/app/app.tsx b/apps/remix-ide-e2e/src/local-plugin/src/app/app.tsx index bc599077f4..88c9bc9646 100644 --- a/apps/remix-ide-e2e/src/local-plugin/src/app/app.tsx +++ b/apps/remix-ide-e2e/src/local-plugin/src/app/app.tsx @@ -1,32 +1,43 @@ - -import React, { useEffect, useState } from 'react' -import { RemixPlugin } from './Client' -import { Logger } from './logger' -import { filePanelProfile } from '@remixproject/plugin-api' -import { filSystemProfile } from '@remixproject/plugin-api' -import { dGitProfile } from '@remixproject/plugin-api' -import { editorProfile } from '@remixproject/plugin-api' -import { settingsProfile } from '@remixproject/plugin-api' -import { networkProfile } from '@remixproject/plugin-api' -import { udappProfile } from '@remixproject/plugin-api' -import { compilerProfile } from '@remixproject/plugin-api' -import { contentImportProfile } from '@remixproject/plugin-api' -import { windowProfile } from '@remixproject/plugin-api' -import { pluginManagerProfile } from '@remixproject/plugin-api' -import { Profile } from '@remixproject/plugin-utils' +import React, {useEffect, useState} from 'react' +import {RemixPlugin} from './Client' +import {Logger} from './logger' +import {filePanelProfile} from '@remixproject/plugin-api' +import {filSystemProfile} from '@remixproject/plugin-api' +import {dGitProfile} from '@remixproject/plugin-api' +import {editorProfile} from '@remixproject/plugin-api' +import {settingsProfile} from '@remixproject/plugin-api' +import {networkProfile} from '@remixproject/plugin-api' +import {udappProfile} from '@remixproject/plugin-api' +import {compilerProfile} from '@remixproject/plugin-api' +import {contentImportProfile} from '@remixproject/plugin-api' +import {windowProfile} from '@remixproject/plugin-api' +import {pluginManagerProfile} from '@remixproject/plugin-api' +import {Profile} from '@remixproject/plugin-utils' import './app.css' const client = new RemixPlugin() -function App () { +function App() { const [payload, setPayload] = useState('') const [log, setLog] = useState() const [started, setStarted] = useState(false) const [events, setEvents] = useState() - const [profiles, setProfiles] = useState([pluginManagerProfile, filePanelProfile, filSystemProfile, dGitProfile, networkProfile, settingsProfile, editorProfile, compilerProfile, udappProfile, contentImportProfile, windowProfile]) + const [profiles, setProfiles] = useState([ + pluginManagerProfile, + filePanelProfile, + filSystemProfile, + dGitProfile, + networkProfile, + settingsProfile, + editorProfile, + compilerProfile, + udappProfile, + contentImportProfile, + windowProfile + ]) - const handleChange = ({ target }: any) => { + const handleChange = ({target}: any) => { setPayload(target.value) } @@ -44,7 +55,7 @@ function App () { const p = await client.call('manager', 'getProfile', name) addProfiles = [...addProfiles, p] } - setProfiles(profiles => [...profiles, ...addProfiles]) + setProfiles((profiles) => [...profiles, ...addProfiles]) profiles.map((profile: Profile) => { if (profile.events) { @@ -77,8 +88,10 @@ function App () { let ob: any = null try { ob = JSON.parse(payload) - if (ob && !Array.isArray(ob)) { ob = [ob] } - } catch (e) { } + if (ob && !Array.isArray(ob)) { + ob = [ob] + } + } catch (e) {} const args = ob || [payload] setStarted(true) setLog('') @@ -97,30 +110,41 @@ function App () { return (
PLUGIN API TESTER
-

+ +

- + - - + + {profiles.map((profile: Profile) => { const methods = profile.methods.map((method: string) => { - return + return ( + + ) }) - const events = profile.events ? profile.events.map((event: string) => { - return - }) : null - return


{methods}

{events ? : null}{events}
+ const events = profile.events + ? profile.events.map((event: string) => { + return ( + + ) + }) + : null + return ( +
+ +

+ {methods} +

+ {events ? : null} + {events} +
+ ) })} -
) } diff --git a/apps/remix-ide-e2e/src/local-plugin/src/app/logger.tsx b/apps/remix-ide-e2e/src/local-plugin/src/app/logger.tsx index 92033e264b..4273c609d2 100644 --- a/apps/remix-ide-e2e/src/local-plugin/src/app/logger.tsx +++ b/apps/remix-ide-e2e/src/local-plugin/src/app/logger.tsx @@ -1,9 +1,13 @@ import React from 'react' interface loggerProps { - log: any, + log: any id: string } export const Logger: React.FC = (props) => { - return (
{props.log}
) + return ( +
+ {props.log} +
+ ) } diff --git a/apps/remix-ide-e2e/src/tests/blockchain.test.ts b/apps/remix-ide-e2e/src/tests/blockchain.test.ts index c44463ee30..7567543d6c 100644 --- a/apps/remix-ide-e2e/src/tests/blockchain.test.ts +++ b/apps/remix-ide-e2e/src/tests/blockchain.test.ts @@ -21,7 +21,7 @@ module.exports = { browser.testContracts('test.sol',{ content: code } , ['A']) .clickLaunchIcon('udapp') .selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite - .click('.udapp_contractActionsContainerSingle > button') + .click('.udapp_contractActionsContainerSingle > div') .clickInstance(0) .clickFunction('foo - call', { types: 'uint256 p', values: '0' }) .perform((done) => { diff --git a/apps/remix-ide-e2e/src/tests/contract_flattener.test.ts b/apps/remix-ide-e2e/src/tests/contract_flattener.test.ts index 20a3699d32..30c9f43c5f 100644 --- a/apps/remix-ide-e2e/src/tests/contract_flattener.test.ts +++ b/apps/remix-ide-e2e/src/tests/contract_flattener.test.ts @@ -42,37 +42,43 @@ const sources = [ 'TestContract.sol': { content: ` // SPDX-License-Identifier: MIT - pragma solidity ^0.8.9; - - import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; - import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; - import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; - import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; - import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; - - contract MyToken is Initializable, ERC721Upgradeable, ERC721BurnableUpgradeable, OwnableUpgradeable, UUPSUpgradeable { - /// @custom:oz-upgrades-unsafe-allow constructor - constructor() { - _disableInitializers(); + pragma solidity ^0.8.20; + + import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; + import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; + import "@openzeppelin/contracts/access/Ownable.sol"; + import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; + + contract MyToken is ERC20, ERC20Burnable, ERC20Pausable, Ownable, ERC20Permit { + constructor(address initialOwner) + ERC20("MyToken", "MTK") + Ownable(initialOwner) + ERC20Permit("MyToken") + {} + + function pause() public onlyOwner { + _pause(); } - - function initialize() initializer public { - __ERC721_init("MyToken", "MTK"); - __ERC721Burnable_init(); - __Ownable_init(); - __UUPSUpgradeable_init(); + + function unpause() public onlyOwner { + _unpause(); } - - function safeMint(address to, uint256 tokenId) public onlyOwner { - _safeMint(to, tokenId); + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); } - - function _authorizeUpgrade(address newImplementation) + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) internal - onlyOwner - override - {} + override(ERC20, ERC20Pausable) + { + super._update(from, to, value); + } } + ` }, } diff --git a/apps/remix-ide-e2e/src/tests/editor.test.ts b/apps/remix-ide-e2e/src/tests/editor.test.ts index 771b59b93a..39a2a2de74 100644 --- a/apps/remix-ide-e2e/src/tests/editor.test.ts +++ b/apps/remix-ide-e2e/src/tests/editor.test.ts @@ -1,16 +1,17 @@ 'use strict' -import { NightwatchBrowser } from 'nightwatch' +import {NightwatchBrowser} from 'nightwatch' import init from '../helpers/init' module.exports = { '@disabled': true, - before: function (browser: NightwatchBrowser, done: VoidFunction) { + 'before': function (browser: NightwatchBrowser, done: VoidFunction) { init(browser, done, 'http://127.0.0.1:8080', true) }, 'Should zoom in editor #group1': function (browser: NightwatchBrowser) { - browser.waitForElementVisible('div[data-id="mainPanelPluginsContainer"]') + browser + .waitForElementVisible('div[data-id="mainPanelPluginsContainer"]') .clickLaunchIcon('filePanel') .waitForElementVisible('div[data-id="filePanelFileExplorerTree"]') .openFile('contracts') @@ -23,7 +24,8 @@ module.exports = { }, 'Should zoom out editor #group1': function (browser: NightwatchBrowser) { - browser.waitForElementVisible('#editorView') + browser + .waitForElementVisible('#editorView') .checkElementStyle('.view-lines', 'font-size', '16px') .click('*[data-id="tabProxyZoomOut"]') .click('*[data-id="tabProxyZoomOut"]') @@ -31,57 +33,72 @@ module.exports = { }, 'Should display compile error in editor #group1': function (browser: NightwatchBrowser) { - browser.waitForElementVisible('#editorView') + browser + .waitForElementVisible('#editorView') .setEditorValue(storageContractWithError + 'error') .pause(2000) - .waitForElementVisible('.margin-view-overlays .fa-exclamation-square', 120000) - .checkAnnotations('fa-exclamation-square', 29) // error + .waitForElementVisible('.glyph-margin-widgets .fa-exclamation-square', 120000) + .checkAnnotations('fa-exclamation-square') // error .clickLaunchIcon('udapp') .checkAnnotationsNotPresent('fa-exclamation-square') // error .clickLaunchIcon('solidity') - .checkAnnotations('fa-exclamation-square', 29) // error + .checkAnnotations('fa-exclamation-square') // error }, - 'Should minimize and maximize codeblock in editor #group1': '' + function (browser: NightwatchBrowser) { - browser.waitForElementVisible('#editorView') - .waitForElementVisible('.ace_open') - .click('.ace_start:nth-of-type(1)') - .waitForElementVisible('.ace_closed') - .click('.ace_start:nth-of-type(1)') - .waitForElementVisible('.ace_open') - }, + 'Should minimize and maximize codeblock in editor #group1': + '' + + function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('#editorView') + .waitForElementVisible('.ace_open') + .click('.ace_start:nth-of-type(1)') + .waitForElementVisible('.ace_closed') + .click('.ace_start:nth-of-type(1)') + .waitForElementVisible('.ace_open') + }, 'Should add breakpoint to editor #group1': function (browser: NightwatchBrowser) { - browser.waitForElementVisible('#editorView') - .waitForElementNotPresent('.margin-view-overlays .fa-circle') - .execute(() => { - (window as any).addRemixBreakpoint(1) - }, [], () => {}) - .waitForElementVisible('.margin-view-overlays .fa-circle') - }, - - 'Should load syntax highlighter for ace light theme #group1': '' + function (browser: NightwatchBrowser) { - browser.waitForElementVisible('#editorView') - .checkElementStyle('.ace_keyword', 'color', aceThemes.light.keyword) - .checkElementStyle('.ace_comment.ace_doc', 'color', aceThemes.light.comment) - .checkElementStyle('.ace_function', 'color', aceThemes.light.function) - .checkElementStyle('.ace_variable', 'color', aceThemes.light.variable) + browser + .waitForElementVisible('#editorView') + .waitForElementNotPresent('.glyph-margin-widgets .fa-circle') + .execute( + () => { + ;(window as any).addRemixBreakpoint(1) + }, + [], + () => {} + ) + .waitForElementVisible('.glyph-margin-widgets .fa-circle') }, - 'Should load syntax highlighter for ace dark theme #group1': '' + function (browser: NightwatchBrowser) { - browser.waitForElementVisible('*[data-id="verticalIconsKindsettings"]') - .click('*[data-id="verticalIconsKindsettings"]') - .waitForElementVisible('*[data-id="settingsTabThemeLabelDark"]') - .click('*[data-id="settingsTabThemeLabelDark"]') - .pause(2000) - .waitForElementVisible('#editorView') - /* @todo(#2863) ch for class and not colors + 'Should load syntax highlighter for ace light theme #group1': + '' + + function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('#editorView') + .checkElementStyle('.ace_keyword', 'color', aceThemes.light.keyword) + .checkElementStyle('.ace_comment.ace_doc', 'color', aceThemes.light.comment) + .checkElementStyle('.ace_function', 'color', aceThemes.light.function) + .checkElementStyle('.ace_variable', 'color', aceThemes.light.variable) + }, + + 'Should load syntax highlighter for ace dark theme #group1': + '' + + function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="verticalIconsKindsettings"]') + .click('*[data-id="verticalIconsKindsettings"]') + .waitForElementVisible('*[data-id="settingsTabThemeLabelDark"]') + .click('*[data-id="settingsTabThemeLabelDark"]') + .pause(2000) + .waitForElementVisible('#editorView') + /* @todo(#2863) ch for class and not colors .checkElementStyle('.ace_keyword', 'color', aceThemes.dark.keyword) .checkElementStyle('.ace_comment.ace_doc', 'color', aceThemes.dark.comment) .checkElementStyle('.ace_function', 'color', aceThemes.dark.function) .checkElementStyle('.ace_variable', 'color', aceThemes.dark.variable) */ - }, + }, 'Should highlight source code #group1': function (browser: NightwatchBrowser) { // include all files here because switching between plugins in side-panel removes highlight @@ -101,22 +118,26 @@ module.exports = { .checkElementStyle('.highlightLine51', 'background-color', 'rgb(52, 152, 219)') }, - 'Should remove 1 highlight from source code #group1': '' + function (browser: NightwatchBrowser) { - browser.waitForElementVisible('li[data-id="treeViewLitreeViewItemremoveSourcehighlightScript.js"]') - .click('li[data-id="treeViewLitreeViewItemremoveSourcehighlightScript.js"]') - .pause(2000) - .executeScriptInTerminal('remix.exeCurrent()') - .waitForElementVisible('li[data-id="treeViewLitreeViewItemcontracts"]') - .click('li[data-id="treeViewLitreeViewItemcontracts"]') - .waitForElementVisible('li[data-id="treeViewLitreeViewItemcontracts/3_Ballot.sol"]') - .click('li[data-id="treeViewLitreeViewItemcontracts/3_Ballot.sol"]') - .waitForElementNotPresent('.highlightLine33', 60000) - .checkElementStyle('.highlightLine41', 'background-color', 'rgb(52, 152, 219)') - .checkElementStyle('.highlightLine51', 'background-color', 'rgb(52, 152, 219)') - }, + 'Should remove 1 highlight from source code #group1': + '' + + function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('li[data-id="treeViewLitreeViewItemremoveSourcehighlightScript.js"]') + .click('li[data-id="treeViewLitreeViewItemremoveSourcehighlightScript.js"]') + .pause(2000) + .executeScriptInTerminal('remix.exeCurrent()') + .waitForElementVisible('li[data-id="treeViewLitreeViewItemcontracts"]') + .click('li[data-id="treeViewLitreeViewItemcontracts"]') + .waitForElementVisible('li[data-id="treeViewLitreeViewItemcontracts/3_Ballot.sol"]') + .click('li[data-id="treeViewLitreeViewItemcontracts/3_Ballot.sol"]') + .waitForElementNotPresent('.highlightLine33', 60000) + .checkElementStyle('.highlightLine41', 'background-color', 'rgb(52, 152, 219)') + .checkElementStyle('.highlightLine51', 'background-color', 'rgb(52, 152, 219)') + }, 'Should remove all highlights from source code #group1': function (browser: NightwatchBrowser) { - browser.waitForElementVisible('li[data-id="treeViewLitreeViewItemremoveAllSourcehighlightScript.js"]') + browser + .waitForElementVisible('li[data-id="treeViewLitreeViewItemremoveAllSourcehighlightScript.js"]') .click('li[data-id="treeViewLitreeViewItemremoveAllSourcehighlightScript.js"]') .pause(2000) .executeScriptInTerminal('remix.exeCurrent()') @@ -126,8 +147,7 @@ module.exports = { .waitForElementNotPresent('.highlightLine33', 60000) .waitForElementNotPresent('.highlightLine41', 60000) .waitForElementNotPresent('.highlightLine51', 60000) - }, - + } } const aceThemes = { @@ -233,5 +253,3 @@ contract Storage { return number; } }` - - diff --git a/apps/remix-ide-e2e/src/tests/editorHoverContext.test.ts b/apps/remix-ide-e2e/src/tests/editorHoverContext.test.ts index db86224b11..dd83159f88 100644 --- a/apps/remix-ide-e2e/src/tests/editorHoverContext.test.ts +++ b/apps/remix-ide-e2e/src/tests/editorHoverContext.test.ts @@ -17,7 +17,6 @@ module.exports = { before: function (browser: NightwatchBrowser, done: VoidFunction) { init(browser, done, 'http://127.0.0.1:8080', false) }, - 'Should load the test file': function (browser: NightwatchBrowser) { browser.openFile('contracts') .openFile('contracts/3_Ballot.sol') @@ -86,7 +85,50 @@ module.exports = { const path = "//*[@class='view-line' and contains(.,'Voter') and contains(.,'struct')]//span//span[contains(.,'Voter')]" const expectedContent = 'StructDefinition' checkEditorHoverContent(browser, path, expectedContent) - } + }, + 'Add token file': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('solidity') + .setSolidityCompilerVersion('soljson-v0.8.20+commit.a1b79de6.js') + .addFile('contracts/mytoken.sol', { + content: myToken + }).useXpath().waitForElementVisible("//*[@class='view-line' and contains(.,'gas')]") + }, + // here we change quickly between files to test the files being parsed correctly when switching between them + 'Should show ERC20 hover over contract in editor #group1': function (browser: NightwatchBrowser) { + browser.scrollToLine(10) + const path = "//*[@class='view-line' and contains(.,'MyToken') and contains(.,'Pausable')]//span//span[contains(.,'ERC20Burnable')]" + const expectedContent = 'contract ERC20Burnable is ERC20Burnable, ERC20, IERC20Errors, IERC20Metadata, IERC20, Context' + checkEditorHoverContent(browser, path, expectedContent, 25) + }, + 'Go back to ballot file': function (browser: NightwatchBrowser) { + browser.openFile('contracts/3_Ballot.sol') + .useXpath().waitForElementVisible("//*[@class='view-line' and contains(.,'gas')]") + }, + 'Should show hover over function in editor again #group1': function (browser: NightwatchBrowser) { + browser + .scrollToLine(58) + const path: string = "//*[@class='view-line' and contains(.,'giveRightToVote(address') and contains(.,'function') and contains(.,'public')]//span//span[contains(.,'giveRightToVote')]" + let expectedContent = 'Estimated execution cost' + checkEditorHoverContent(browser, path, expectedContent) + expectedContent = 'function giveRightToVote (address internal voter) public nonpayable returns ()' + checkEditorHoverContent(browser, path, expectedContent) + expectedContent = "@dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'" + checkEditorHoverContent(browser, path, expectedContent) + }, + 'Open token file': function (browser: NightwatchBrowser) { + browser.openFile('contracts/mytoken.sol') + .useXpath().waitForElementVisible("//*[@class='view-line' and contains(.,'gas')]") + }, + 'Should show ERC20 hover over contract in editor again #group1': function (browser: NightwatchBrowser) { + browser.scrollToLine(10) + const path = "//*[@class='view-line' and contains(.,'MyToken') and contains(.,'Pausable')]//span//span[contains(.,'ERC20Burnable')]" + const expectedContent = 'contract ERC20Burnable is ERC20Burnable, ERC20, IERC20Errors, IERC20Metadata, IERC20, Context' + checkEditorHoverContent(browser, path, expectedContent, 25) + }, + + + } @@ -233,4 +275,45 @@ contract BallotHoverTest { winnerName_ = proposals[winningProposal()].name; } } +` + +const myToken = ` +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; + +contract MyToken is ERC20, ERC20Burnable, ERC20Pausable, Ownable, ERC20Permit { + constructor(address initialOwner) + ERC20("MyToken", "MTK") + Ownable(initialOwner) + ERC20Permit("MyToken") + {} + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + + // The following functions are overrides required by Solidity. + + function _update(address from, address to, uint256 value) + internal + override(ERC20, ERC20Pausable) + { + super._update(from, to, value); + } +} + ` \ No newline at end of file diff --git a/apps/remix-ide-e2e/src/tests/editorReferences.test.ts b/apps/remix-ide-e2e/src/tests/editorReferences.test.ts index 86856a9822..51a3edc058 100644 --- a/apps/remix-ide-e2e/src/tests/editorReferences.test.ts +++ b/apps/remix-ide-e2e/src/tests/editorReferences.test.ts @@ -1,53 +1,55 @@ 'use strict' -import { NightwatchBrowser } from 'nightwatch' +import {NightwatchBrowser} from 'nightwatch' import init from '../helpers/init' const openReferences = (browser: NightwatchBrowser, path: string) => { - (browser as any).useXpath() - .useXpath() - .waitForElementVisible(path) - .click(path) - .perform(function () { - const actions = this.actions({ async: true }); - return actions. - keyDown(this.Keys.SHIFT). - sendKeys(this.Keys.F12) - }) + ;(browser as any) + .useXpath() + .useXpath() + .waitForElementVisible(path) + .click(path) + .perform(function () { + const actions = this.actions({async: true}) + return actions.keyDown(this.Keys.SHIFT).sendKeys(this.Keys.F12) + }) } module.exports = { - before: function (browser: NightwatchBrowser, done: VoidFunction) { - init(browser, done, 'http://127.0.0.1:8080', false) - }, - - 'Should load the test file': function (browser: NightwatchBrowser) { - browser.openFile('contracts') - .openFile('contracts/3_Ballot.sol') - .waitForElementVisible('#editorView') - .setEditorValue(BallotWithARefToOwner) - .pause(10000) // wait for the compiler to finish - .scrollToLine(37) - }, - 'Should show local references': function (browser: NightwatchBrowser) { - browser.scrollToLine(48) - const path = "//*[@class='view-line' and contains(.,'length') and contains(.,'proposalNames')]//span//span[contains(.,'proposalNames')]" - openReferences(browser, path) - browser.waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch']//span[contains(.,'length; i++')]") - .waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch']//span[contains(.,'name:')]") - .waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch']//span[contains(.,'constructor')]") - .keys(browser.Keys.ESCAPE) - }, - 'Should show references of getOwner': function (browser: NightwatchBrowser) { - browser.scrollToLine(39) - const path = "//*[@class='view-line' and contains(.,'getOwner') and contains(.,'cowner')]//span//span[contains(.,'getOwner')]" - openReferences(browser, path) - browser.useXpath() - .waitForElementVisible("//*[@class='monaco-highlighted-label']//span[contains(.,'2_Owner.sol')]") - .waitForElementVisible("//*[@class='monaco-highlighted-label']//span[contains(.,'3_Ballot.sol')]") - .waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch']//span[contains(.,'cowner.getOwner')]") - .waitForElementVisible("//*[contains(@class, 'results-loaded') and contains(., 'References (2)')]") - .keys(browser.Keys.ESCAPE) - } + 'before': function (browser: NightwatchBrowser, done: VoidFunction) { + init(browser, done, 'http://127.0.0.1:8080', false) + }, + + 'Should load the test file': function (browser: NightwatchBrowser) { + browser + .openFile('contracts') + .openFile('contracts/3_Ballot.sol') + .waitForElementVisible('#editorView') + .setEditorValue(BallotWithARefToOwner) + .pause(10000) // wait for the compiler to finish + .scrollToLine(37) + }, + 'Should show local references': function (browser: NightwatchBrowser) { + browser.scrollToLine(48) + const path = "//*[@class='view-line' and contains(.,'length') and contains(.,'proposalNames')]//span//span[contains(.,'proposalNames')]" + openReferences(browser, path) + browser + .waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch'][contains(.,'length; i++')]") + .waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch'][contains(.,'name:')]") + .waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch'][contains(.,'constructor')]") + .keys(browser.Keys.ESCAPE) + }, + 'Should show references of getOwner': function (browser: NightwatchBrowser) { + browser.scrollToLine(39) + const path = "//*[@class='view-line' and contains(.,'getOwner') and contains(.,'cowner')]//span//span[contains(.,'getOwner')]" + openReferences(browser, path) + browser + .useXpath() + .waitForElementVisible("//*[@class='monaco-highlighted-label'][contains(.,'2_Owner.sol')]") + .waitForElementVisible("//*[@class='monaco-highlighted-label'][contains(.,'3_Ballot.sol')]") + .waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch'][contains(.,'cowner.getOwner')]") + .waitForElementVisible("//*[contains(@class, 'results-loaded') and contains(., 'References (2)')]") + .keys(browser.Keys.ESCAPE) + } } // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -193,4 +195,4 @@ contract BallotHoverTest { winnerName_ = proposals[winningProposal()].name; } } -` \ No newline at end of file +` diff --git a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts index 26a2e7cffd..38d1cfc5c1 100644 --- a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts @@ -42,6 +42,25 @@ module.exports = { }) }, + 'Should execute `writeMultipleFiles` api from file manager external api #group1': function (browser: NightwatchBrowser) { + browser + .addFile('writeMultipleFiles.js', { content: executeWriteMultipleFiles }) + .executeScriptInTerminal('remix.exeCurrent()') + .pause(2000) + .openFile('contracts/new_contract_1.sol') + .getEditorValue((content) => { + browser.assert.ok(content.indexOf('pragma solidity ^0.6.0') !== -1, 'content does not contain "pragma solidity ^0.6.0"') + }) + .openFile('new_contract_2.sol') + .getEditorValue((content) => { + browser.assert.ok(content.indexOf('pragma solidity ^0.8.0') !== -1, 'content does not contain "pragma solidity ^0.8.0"') + }) + .openFile('testing.txt') + .getEditorValue((content) => { + browser.assert.ok(content.indexOf('test') !== -1, 'content does not contain "test"') + }) + }, + 'Should execute `readFile` api from file manager external api #group2': function (browser: NightwatchBrowser) { browser .addFile('writeFile.js', { content: executeWriteFile }) @@ -143,6 +162,14 @@ const executeWriteFile = ` run() ` +const executeWriteMultipleFiles = ` + const run = async () => { + await remix.call('fileManager', 'writeMultipleFiles', ['contracts/new_contract_1.sol', 'new_contract_2.sol', 'testing.txt'], ['pragma solidity ^0.6.0', 'pragma solidity ^0.8.0', 'test'], '/') + } + + run() +` + const executeReadFile = ` const run = async () => { const result = await remix.call('fileManager', 'readFile', 'new_contract.sol') diff --git a/apps/remix-ide-e2e/src/tests/proxy_oz_v4.test.ts b/apps/remix-ide-e2e/src/tests/proxy_oz_v4.test.ts new file mode 100644 index 0000000000..f4d21d6cbd --- /dev/null +++ b/apps/remix-ide-e2e/src/tests/proxy_oz_v4.test.ts @@ -0,0 +1,345 @@ +'use strict' +import { NightwatchBrowser } from 'nightwatch' +import init from '../helpers/init' + +let firstProxyAddress: string +let lastProxyAddress: string +let shortenedFirstAddress: string +let shortenedLastAddress: string +module.exports = { + '@disabled': true, + before: function (browser: NightwatchBrowser, done: VoidFunction) { + init(browser, done) + }, + + '@sources': function () { + return sources + }, + + 'Should set the compiler version to 8.19': function(browser: NightwatchBrowser) { + browser.setSolidityCompilerVersion('soljson-v0.8.19+commit.7dd6d404.js') + }, + + 'Should show deploy proxy option for UUPS upgradeable contract #group1': function (browser: NightwatchBrowser) { + browser + .addFile('myTokenV1.sol', sources[0]['myTokenV1.sol']) + .clickLaunchIcon('solidity') + .pause(2000) + // because the compilatiom imports are slow and sometimes stop loading (not sure why, it's bug) we need to recompile and check to see if the files are really in de FS + .click('[data-id="compilerContainerCompileBtn"]') + .clickLaunchIcon('filePanel') + .isVisible({ + selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable@4.8.3/proxy/beacon/IBeaconUpgradeable.sol"]', + timeout: 120000, + suppressNotFoundErrors: true + }) + .clickLaunchIcon('solidity') + .click('[data-id="compilerContainerCompileBtn"]') + .clickLaunchIcon('filePanel') + .isVisible({ + selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable@4.8.3/proxy/beacon/IBeaconUpgradeable.sol"]', + timeout: 120000, + suppressNotFoundErrors: true + }) + .clickLaunchIcon('solidity') + .click('[data-id="compilerContainerCompileBtn"]') + .clickLaunchIcon('filePanel') + .waitForElementVisible({ + selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable@4.8.3/proxy/beacon/IBeaconUpgradeable.sol"]', + timeout: 120000, + }) + .clickLaunchIcon('solidity') + .waitForElementPresent('select[id="compiledContracts"] option[value=MyToken]', 60000) + .clickLaunchIcon('udapp') + .click('select.udapp_contractNames') + .click('select.udapp_contractNames option[value=MyToken]') + .waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]') + .waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]') + }, + + 'Should show upgrade proxy option for child contract inheriting UUPS parent contract #group1': function (browser: NightwatchBrowser) { + browser + .addFile('myTokenV2.sol', sources[1]['myTokenV2.sol']) + .clickLaunchIcon('solidity') + .assert.visible('[data-id="compilerContainerCompileBtn"]') + .click('[data-id="compilerContainerCompileBtn"]') + .waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000) + .clickLaunchIcon('udapp') + .click('select.udapp_contractNames') + .click('select.udapp_contractNames option[value=MyTokenV2]') + .waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]') + .waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]') + }, + + 'Should deploy proxy without initialize parameters #group1': function (browser: NightwatchBrowser) { + browser + .openFile('myTokenV1.sol') + .clickLaunchIcon('solidity') + .assert.visible('[data-id="compilerContainerCompileBtn"]') + .click('[data-id="compilerContainerCompileBtn"]') + .waitForElementPresent('select[id="compiledContracts"] option[value=MyToken]', 60000) + .clickLaunchIcon('udapp') + .click('select.udapp_contractNames') + .click('select.udapp_contractNames option[value=MyToken]') + .verify.visible('[data-id="contractGUIDeployWithProxyLabel"]') + .waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]') + .click('[data-id="contractGUIDeployWithProxyLabel"]') + .createContract('') + .waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)') + .waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') + .click('[data-id="udappNotify-modal-footer-ok-react"]') + .waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Deploy Proxy (ERC1967)') + .waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') + .click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') + .waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') + .waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') + .waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 < 5.0.0 as proxy...', 60000) + }, + + 'Should interact with deployed contract via ERC1967 (proxy) #group1': function (browser: NightwatchBrowser) { + browser + .getAddressAtPosition(1, (address) => { + firstProxyAddress = address + shortenedFirstAddress = address.slice(0, 5) + '...' + address.slice(address.length - 5, address.length) + }) + .clickInstance(1) + .perform((done) => { + browser.testConstantFunction(firstProxyAddress, 'name - call', null, '0:\nstring: MyToken').perform(() => { + done() + }) + }) + .perform((done) => { + browser.testConstantFunction(firstProxyAddress, 'symbol - call', null, '0:\nstring: MTK').perform(() => { + done() + }) + }) + }, + + 'Should deploy proxy with initialize parameters #group1': function (browser: NightwatchBrowser) { + browser + .waitForElementPresent('[data-id="deployAndRunClearInstances"]') + .click('[data-id="deployAndRunClearInstances"]') + .addFile('initializeProxy.sol', sources[2]['initializeProxy.sol']) + .clickLaunchIcon('solidity') + .assert.visible('[data-id="compilerContainerCompileBtn"]') + .click('[data-id="compilerContainerCompileBtn"]') + .waitForElementPresent('select[id="compiledContracts"] option[value=MyInitializedToken]', 60000) + .clickLaunchIcon('udapp') + .click('select.udapp_contractNames') + .click('select.udapp_contractNames option[value=MyInitializedToken]') + .waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]') + .click('[data-id="contractGUIDeployWithProxyLabel"]') + .useXpath() + .waitForElementPresent('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[1]/input') + .waitForElementPresent('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[2]/input') + .setValue('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[1]/input', 'Remix') + .setValue('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[2]/input', "R") + .useCss() + .createContract('') + .waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)') + .waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') + .click('[data-id="udappNotify-modal-footer-ok-react"]') + .waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Deploy Proxy (ERC1967)') + .waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') + .click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') + .waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') + .waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') + .waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 < 5.0.0 as proxy...', 60000) + }, + + 'Should interact with initialized contract to verify parameters #group1': function (browser: NightwatchBrowser) { + browser + .getAddressAtPosition(1, (address) => { + lastProxyAddress = address + shortenedLastAddress = address.slice(0, 5) + '...' + address.slice(address.length - 5, address.length) + }) + .clickInstance(1) + .perform((done) => { + browser.testConstantFunction(lastProxyAddress, 'name - call', null, '0:\nstring: Remix').perform(() => { + done() + }) + }) + .perform((done) => { + browser.testConstantFunction(lastProxyAddress, 'symbol - call', null, '0:\nstring: R').perform(() => { + done() + }) + }) + }, + + 'Should upgrade contract by selecting a previously deployed proxy address from dropdown (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="terminalClearConsole"]') + .waitForElementPresent('[data-id="deployAndRunClearInstances"]') + .click('[data-id="deployAndRunClearInstances"]') + .openFile('myTokenV2.sol') + .clickLaunchIcon('solidity') + .assert.visible('[data-id="compilerContainerCompileBtn"]') + .click('[data-id="compilerContainerCompileBtn"]') + .waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000) + .clickLaunchIcon('udapp') + .click('select.udapp_contractNames') + .click('select.udapp_contractNames option[value=MyTokenV2]') + .waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]') + .click('[data-id="contractGUIUpgradeImplementationLabel"]') + .waitForElementPresent('[data-id="toggleProxyAddressDropdown"]') + .click('[data-id="toggleProxyAddressDropdown"]') + .waitForElementVisible('[data-id="proxy-dropdown-items"]') + .assert.textContains('[data-id="proxy-dropdown-items"]', shortenedFirstAddress) + .assert.textContains('[data-id="proxy-dropdown-items"]', shortenedLastAddress) + .click('[data-id="proxyAddress1"]') + .createContract('') + .waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Update Proxy') + .waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') + .click('[data-id="udappNotify-modal-footer-ok-react"]') + .waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Update Proxy (ERC1967)') + .waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') + .click( + { + selector: '[data-id="confirmProxyDeployment-modal-footer-ok-react"]', + }) + .waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') + .waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') + .waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 < 5.0.0 for the proxy upgrade..', 60000) + }, + + 'Should interact with upgraded function in contract MyTokenV2 #group1': function (browser: NightwatchBrowser) { + browser + .clickInstance(1) + .perform((done) => { + browser.testConstantFunction(lastProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => { + done() + }) + }) + }, + + 'Should upgrade contract by providing proxy address in input field (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="terminalClearConsole"]') + .waitForElementPresent('[data-id="deployAndRunClearInstances"]') + .click('[data-id="deployAndRunClearInstances"]') + .openFile('myTokenV2.sol') + .clickLaunchIcon('solidity') + .assert.visible('[data-id="compilerContainerCompileBtn"]') + .click('[data-id="compilerContainerCompileBtn"]') + .waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000) + .clickLaunchIcon('udapp') + .click('select.udapp_contractNames') + .click('select.udapp_contractNames option[value=MyTokenV2]') + .waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]') + .waitForElementPresent('[data-id="toggleProxyAddressDropdown"]') + .clearValue('[data-id="ERC1967AddressInput"]') + .setValue('[data-id="ERC1967AddressInput"]', firstProxyAddress) + .createContract('') + .waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Update Proxy') + .waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') + .click('[data-id="udappNotify-modal-footer-ok-react"]') + .waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Update Proxy (ERC1967)') + .waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') + .click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') + .waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') + .waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') + .waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 < 5.0.0 for the proxy upgrade..', 60000) + }, + + 'Should interact with upgraded contract through provided proxy address #group1': function (browser: NightwatchBrowser) { + browser + .clearConsole() + .clickInstance(1) + .perform((done) => { + browser.testConstantFunction(firstProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => { + done() + }) + }) + }, + 'Should debug the call': function(browser: NightwatchBrowser) { + browser + .debugTransaction(0) + .waitForElementVisible({ + locateStrategy: 'xpath', + selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"11")]', + timeout: 60000 + }) + .goToVMTraceStep(146) + .waitForElementContainsText('*[data-id="functionPanel"]', 'version()', 60000) + .end() + } +} + + +const sources = [ + { + 'myTokenV1.sol': { + content: ` + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.4; + + import "@openzeppelin/contracts-upgradeable@4.8.3/token/ERC721/ERC721Upgradeable.sol"; + import "@openzeppelin/contracts-upgradeable@4.8.3/access/OwnableUpgradeable.sol"; + import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/Initializable.sol"; + import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/UUPSUpgradeable.sol"; + + contract MyToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize() initializer public { + __ERC721_init("MyToken", "MTK"); + __Ownable_init(); + __UUPSUpgradeable_init(); + } + + function _authorizeUpgrade(address newImplementation) + internal + onlyOwner + override + {} + } + ` + } + }, { + 'myTokenV2.sol': { + content: ` + import "./myTokenV1.sol"; + + contract MyTokenV2 is MyToken { + function version () public view returns (string memory) { + return "MyTokenV2!"; + } + } + ` + } + }, { + 'initializeProxy.sol': { + content: ` + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.4; + + import "@openzeppelin/contracts-upgradeable@4.8.3/token/ERC721/ERC721Upgradeable.sol"; + import "@openzeppelin/contracts-upgradeable@4.8.3/access/OwnableUpgradeable.sol"; + import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/Initializable.sol"; + import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/UUPSUpgradeable.sol"; + + contract MyInitializedToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(string memory tokenName, string memory tokenSymbol) initializer public { + __ERC721_init(tokenName, tokenSymbol); + __Ownable_init(); + __UUPSUpgradeable_init(); + } + + function _authorizeUpgrade(address newImplementation) + internal + onlyOwner + override + {} + } + ` + } + } +] \ No newline at end of file diff --git a/apps/remix-ide-e2e/src/tests/proxy.test.ts b/apps/remix-ide-e2e/src/tests/proxy_oz_v5.test.ts similarity index 89% rename from apps/remix-ide-e2e/src/tests/proxy.test.ts rename to apps/remix-ide-e2e/src/tests/proxy_oz_v5.test.ts index 6707b60627..dbe0052e73 100644 --- a/apps/remix-ide-e2e/src/tests/proxy.test.ts +++ b/apps/remix-ide-e2e/src/tests/proxy_oz_v5.test.ts @@ -26,7 +26,7 @@ module.exports = { .click('[data-id="compilerContainerCompileBtn"]') .clickLaunchIcon('filePanel') .isVisible({ - selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol"]', + selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"]', timeout: 120000, suppressNotFoundErrors: true }) @@ -34,7 +34,7 @@ module.exports = { .click('[data-id="compilerContainerCompileBtn"]') .clickLaunchIcon('filePanel') .isVisible({ - selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol"]', + selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"]', timeout: 120000, suppressNotFoundErrors: true }) @@ -42,7 +42,7 @@ module.exports = { .click('[data-id="compilerContainerCompileBtn"]') .clickLaunchIcon('filePanel') .waitForElementVisible({ - selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol"]', + selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"]', timeout: 120000, }) .clickLaunchIcon('solidity') @@ -81,6 +81,7 @@ module.exports = { .verify.visible('[data-id="contractGUIDeployWithProxyLabel"]') .waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]') .click('[data-id="contractGUIDeployWithProxyLabel"]') + .setValue('[data-id="initializeInputs-initialOwner"]', '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4') .createContract('') .waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)') .waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') @@ -90,6 +91,7 @@ module.exports = { .click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') .waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') .waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') + .waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 >= 5.0.0 as proxy...') }, 'Should interact with deployed contract via ERC1967 (proxy) #group1': function (browser: NightwatchBrowser) { @@ -131,6 +133,7 @@ module.exports = { .setValue('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[1]/input', 'Remix') .setValue('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[2]/input', "R") .useCss() + .setValue('[data-id="initializeInputs-initialOwner"]', '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4') .createContract('') .waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)') .waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') @@ -140,6 +143,7 @@ module.exports = { .click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') .waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') .waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') + .waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 >= 5.0.0 as proxy...') }, 'Should interact with initialized contract to verify parameters #group1': function (browser: NightwatchBrowser) { @@ -163,6 +167,7 @@ module.exports = { 'Should upgrade contract by selecting a previously deployed proxy address from dropdown (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) { browser + .click('*[data-id="terminalClearConsole"]') .waitForElementPresent('[data-id="deployAndRunClearInstances"]') .click('[data-id="deployAndRunClearInstances"]') .openFile('myTokenV2.sol') @@ -180,6 +185,7 @@ module.exports = { .waitForElementVisible('[data-id="proxy-dropdown-items"]') .assert.textContains('[data-id="proxy-dropdown-items"]', shortenedFirstAddress) .assert.textContains('[data-id="proxy-dropdown-items"]', shortenedLastAddress) + .click('[data-id="proxyAddress1"]') .createContract('') .waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Update Proxy') @@ -193,6 +199,7 @@ module.exports = { }) .waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') .waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') + .waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 >= 5.0.0 for the proxy upgrade...') }, 'Should interact with upgraded function in contract MyTokenV2 #group1': function (browser: NightwatchBrowser) { @@ -207,6 +214,7 @@ module.exports = { 'Should upgrade contract by providing proxy address in input field (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) { browser + .click('*[data-id="terminalClearConsole"]') .waitForElementPresent('[data-id="deployAndRunClearInstances"]') .click('[data-id="deployAndRunClearInstances"]') .openFile('myTokenV2.sol') @@ -230,17 +238,30 @@ module.exports = { .click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') .waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') .waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') + .waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 >= 5.0.0 for the proxy upgrade...') }, 'Should interact with upgraded contract through provided proxy address #group1': function (browser: NightwatchBrowser) { browser + .clearConsole() .clickInstance(1) .perform((done) => { browser.testConstantFunction(firstProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => { done() }) }) - .end() + }, + 'Should debug the call': function(browser: NightwatchBrowser) { + browser + .debugTransaction(0) + .waitForElementVisible({ + locateStrategy: 'xpath', + selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"7")]', + timeout: 60000 + }) + .goToVMTraceStep(129) + .waitForElementContainsText('*[data-id="functionPanel"]', 'version()', 60000) + .end() } } @@ -250,11 +271,11 @@ const sources = [ 'myTokenV1.sol': { content: ` // SPDX-License-Identifier: MIT - pragma solidity ^0.8.4; + pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; - import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; contract MyToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable { @@ -263,9 +284,9 @@ const sources = [ _disableInitializers(); } - function initialize() initializer public { + function initialize(address initialOwner) initializer public { __ERC721_init("MyToken", "MTK"); - __Ownable_init(); + __Ownable_init(initialOwner); __UUPSUpgradeable_init(); } @@ -280,6 +301,8 @@ const sources = [ }, { 'myTokenV2.sol': { content: ` + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.20; import "./myTokenV1.sol"; contract MyTokenV2 is MyToken { @@ -293,11 +316,11 @@ const sources = [ 'initializeProxy.sol': { content: ` // SPDX-License-Identifier: MIT - pragma solidity ^0.8.4; + pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; - import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; contract MyInitializedToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable { @@ -306,9 +329,9 @@ const sources = [ _disableInitializers(); } - function initialize(string memory tokenName, string memory tokenSymbol) initializer public { + function initialize(string memory tokenName, string memory tokenSymbol, address initialOwner) initializer public { __ERC721_init(tokenName, tokenSymbol); - __Ownable_init(); + __Ownable_init(initialOwner); __UUPSUpgradeable_init(); } diff --git a/apps/remix-ide-e2e/src/tests/remixd.test.ts b/apps/remix-ide-e2e/src/tests/remixd.test.ts index 898c020e2c..e8155e05e6 100644 --- a/apps/remix-ide-e2e/src/tests/remixd.test.ts +++ b/apps/remix-ide-e2e/src/tests/remixd.test.ts @@ -104,7 +104,7 @@ module.exports = { }) .addFile('test_import_node_modules_with_github_import.sol', sources[4]['test_import_node_modules_with_github_import.sol']) .clickLaunchIcon('solidity') - .setSolidityCompilerVersion('soljson-v0.8.20+commit.a1b79de6.js') // open-zeppelin moved to pragma ^0.8.0 (master branch) + .setSolidityCompilerVersion('soljson-v0.8.20+commit.a1b79de6.js') // open-zeppelin moved to pragma ^0.8.20 .testContracts('test_import_node_modules_with_github_import.sol', sources[4]['test_import_node_modules_with_github_import.sol'], ['ERC20', 'test11']) }, 'Static Analysis run with remixd #group3': '' + function (browser) { diff --git a/apps/remix-ide-e2e/src/tests/sol2uml.test.ts b/apps/remix-ide-e2e/src/tests/sol2uml.test.ts index a0e1eddb7e..fc33a0df3a 100644 --- a/apps/remix-ide-e2e/src/tests/sol2uml.test.ts +++ b/apps/remix-ide-e2e/src/tests/sol2uml.test.ts @@ -22,15 +22,10 @@ module.exports = { .rightClick('*[data-id="treeViewLitreeViewItemsecondContract.sol"]') .click('*[id="menuitemgeneratecustomaction"') .waitForElementVisible('*[id="sol-uml-gen"]') - .isVisible('*[data-id="treeViewLitreeViewItemsecondContract_flattened.sol"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemsecondContract_flattened.sol"]') }, 'Zoom into uml diagram #group1': function (browser: NightwatchBrowser) { - browser.addFile('secondContract.sol', sources[1]['secondContract.sol']) - .waitForElementVisible('*[data-id="treeViewLitreeViewItemsecondContract.sol"') - .pause(3000) - .rightClick('*[data-id="treeViewLitreeViewItemsecondContract.sol"]') - .click('*[id="menuitemgeneratecustomaction"') - .waitForElementVisible('*[id="sol-uml-gen"]') + browser .click('*[data-id="umlZoominbtn"]') } } @@ -182,37 +177,38 @@ contract Ballot { { 'secondContract.sol': { content: ` - // SPDX-License-Identifier: MIT -pragma solidity ^0.8.9; - -import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; - -contract MyToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable { - /// @custom:oz-upgrades-unsafe-allow constructor - constructor() { - _disableInitializers(); - } + // SPDX-License-Identifier: GPL-3.0 - function initialize() initializer public { - __ERC721_init("MyToken", "MTK"); - __Ownable_init(); - __UUPSUpgradeable_init(); - } +pragma solidity ^0.5.9; - function safeMint(address to, uint256 tokenId) public onlyOwner { - _safeMint(to, tokenId); - 1 + 1; - } +import "@0x/contracts-erc20/contracts/src/ERC20Token.sol"; - function _authorizeUpgrade(address newImplementation) - internal - onlyOwner - override - {} +/** + * @title SampleERC20 + * @dev Create a sample ERC20 standard token + */ +contract SampleERC20 is ERC20Token { + + string public name; + string public symbol; + uint256 public decimals; + + constructor ( + string memory _name, + string memory _symbol, + uint256 _decimals, + uint256 _totalSupply + ) + public + { + name = _name; + symbol = _symbol; + decimals = _decimals; + _totalSupply = _totalSupply; + balances[msg.sender] = _totalSupply; + } } + `} } ] diff --git a/apps/remix-ide-e2e/src/tests/solidityImport.test.ts b/apps/remix-ide-e2e/src/tests/solidityImport.test.ts index 6e7430f0a5..cd86bd7bdd 100644 --- a/apps/remix-ide-e2e/src/tests/solidityImport.test.ts +++ b/apps/remix-ide-e2e/src/tests/solidityImport.test.ts @@ -38,7 +38,7 @@ module.exports = { 'Test GitHub Import - from master branch #group1': function (browser: NightwatchBrowser) { browser - .setSolidityCompilerVersion('soljson-v0.8.20+commit.a1b79de6.js') // open-zeppelin moved to pragma ^0.8.0 (master branch) + .setSolidityCompilerVersion('soljson-v0.8.20+commit.a1b79de6.js') // open-zeppelin moved to pragma ^0.8.20 (master branch) .addFile('Untitled4.sol', sources[3]['Untitled4.sol']) .clickLaunchIcon('filePanel') .verifyContracts(['test7', 'ERC20'], { wait: 10000 }) @@ -54,7 +54,7 @@ module.exports = { 'Test GitHub Import - no branch specified #group2': function (browser: NightwatchBrowser) { browser - .setSolidityCompilerVersion('soljson-v0.8.20+commit.a1b79de6.js') // open-zeppelin moved to pragma ^0.8.0 (master branch) + .setSolidityCompilerVersion('soljson-v0.8.20+commit.a1b79de6.js') // open-zeppelin moved to pragma ^0.8.20 (master branch) .clickLaunchIcon('filePanel') .click('li[data-id="treeViewLitreeViewItemREADME.txt"') .addFile('Untitled6.sol', sources[5]['Untitled6.sol']) @@ -64,7 +64,7 @@ module.exports = { 'Test GitHub Import - raw URL #group4': function (browser: NightwatchBrowser) { browser - .setSolidityCompilerVersion('soljson-v0.8.20+commit.a1b79de6.js') // open-zeppelin moved to pragma ^0.8.0 (master branch) + .setSolidityCompilerVersion('soljson-v0.8.20+commit.a1b79de6.js') // open-zeppelin moved to pragma ^0.8.20 (master branch) .clickLaunchIcon('filePanel') .click('li[data-id="treeViewLitreeViewItemREADME.txt"') .addFile('Untitled7.sol', sources[6]['Untitled7.sol']) diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts index 18295838cd..fc3253614d 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts @@ -238,8 +238,8 @@ module.exports = { }) .addFile('tests/hhLogs_test.sol', sources[0]['tests/hhLogs_test.sol']) .clickLaunchIcon('solidityUnitTesting') - .waitForElementVisible('*[id="singleTesttests/Ballot_test.sol"]', 60000) - .click('*[id="singleTesttests/Ballot_test.sol"]') + .waitForElementVisible('*[id="idsingleTesttests/Ballot_test.sol"]', 60000) + .click('*[id="idsingleTesttests/Ballot_test.sol"]') .click('#runTestsTabRunAction') .pause(2000) .waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000) @@ -261,8 +261,8 @@ module.exports = { .waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]') .addFile('tests/ballotFailedLog_test.sol', sources[0]['tests/ballotFailedLog_test.sol']) .clickLaunchIcon('solidityUnitTesting') - .waitForElementVisible('*[id="singleTesttests/Ballot_test.sol"]', 60000) - .click('*[id="singleTesttests/Ballot_test.sol"]') + .waitForElementVisible('*[id="idsingleTesttests/Ballot_test.sol"]', 60000) + .click('*[id="idsingleTesttests/Ballot_test.sol"]') .click('#runTestsTabRunAction') .pause(2000) .waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000) @@ -278,8 +278,8 @@ module.exports = { .waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]') .addFile('tests/ballotFailedDebug_test.sol', sources[0]['tests/ballotFailedDebug_test.sol']) .clickLaunchIcon('solidityUnitTesting') - .waitForElementVisible('*[id="singleTesttests/Ballot_test.sol"]', 60000) - .click('*[id="singleTesttests/Ballot_test.sol"]') + .waitForElementVisible('*[id="idsingleTesttests/Ballot_test.sol"]', 60000) + .click('*[id="idsingleTesttests/Ballot_test.sol"]') .click('#runTestsTabRunAction') .waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000) .waitForElementContainsText('#solidityUnittestsOutput', 'tests/ballotFailedDebug_test.sol', 60000) diff --git a/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts b/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts index 446ea13622..9a12195b6e 100644 --- a/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts +++ b/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts @@ -33,29 +33,32 @@ module.exports = { }, 'run analysis and filter results': function (browser: NightwatchBrowser) { browser - .clickLaunchIcon('filePanel') - .click('*[data-id="treeViewLitreeViewItemcontracts"]') - .click('*[data-id="treeViewLitreeViewItemcontracts/2_Owner.sol"]') - .clickLaunchIcon('solidity') - .click('*[id="compileBtn"]') - .pause(10000) - .clickLaunchIcon('solidityStaticAnalysis') - .click('*[id="staticAnalysisRunBtn"]') - .waitForElementPresent('#staticanalysisresult .warning', 5000) - // Check warning count - .click('*[data-rb-event-key="remix"]') - .assert.containsText('span#ssaRemixtab > *[data-id="RemixStaticAnalysisErrorCount"]', '1') - .verify.elementPresent('input[name="showLibWarnings"]') - .verify.not.elementPresent('input[name="showLibWarnings"]:checked') - .verify.elementPresent('label[id="headingshowLibWarnings"]') - .click('label[id="headingshowLibWarnings"]') - .pause(1000) - .click('*[data-rb-event-key="remix"]') - .assert.containsText('span#ssaRemixtab > *[data-id="RemixStaticAnalysisErrorCount', '382') - .click('label[id="headingshowLibWarnings"]') - .pause(1000) - .assert.containsText('span#ssaRemixtab > *[data-id="RemixStaticAnalysisErrorCount', '1') - .end() + .clickLaunchIcon('filePanel') + .click('*[data-id="treeViewLitreeViewItemcontracts"]') + .click('*[data-id="treeViewLitreeViewItemcontracts/2_Owner.sol"]') + .clickLaunchIcon('solidity') + .click('*[id="compileBtn"]') + .pause(10000) + .clickLaunchIcon('solidityStaticAnalysis') + .useXpath() + .click('//*[@id="staticAnalysisRunBtn"]') + // .waitForElementPresent('div#staticanalysisresult .warning', 5000) + .waitForElementPresent('//*[@id="staticanalysisresult"]', 5000) + .useCss() + // Check warning count + .click('*[data-rb-event-key="remix"]') + .assert.containsText('span#ssaRemixtab > *[data-id="RemixStaticAnalysisErrorCount"]', '1') + .verify.elementPresent('input[name="showLibWarnings"]') + .verify.not.elementPresent('input[name="showLibWarnings"]:checked') + .verify.elementPresent('label[id="headingshowLibWarnings"]') + .click('label[id="headingshowLibWarnings"]') + .pause(1000) + .click('*[data-rb-event-key="remix"]') + .assert.containsText('span#ssaRemixtab > *[data-id="RemixStaticAnalysisErrorCount', '386') + .click('label[id="headingshowLibWarnings"]') + .pause(1000) + .assert.containsText('span#ssaRemixtab > *[data-id="RemixStaticAnalysisErrorCount', '1') + .end() } } @@ -72,8 +75,8 @@ function runTests (browser: NightwatchBrowser) { 'Fallback function of contract TooMuchGas requires too much gas', 'TooMuchGas.() : Variables have very similar names "test" and "test1".', 'TooMuchGas.() : Variables have very similar names "test" and "test1".'], - '#staticanalysisresult .warning', - browser + '#staticanalysisresult .warning', + browser ) }) } diff --git a/apps/remix-ide-e2e/src/tests/terminal.test.ts b/apps/remix-ide-e2e/src/tests/terminal.test.ts index 0e64b513da..949cfbf913 100644 --- a/apps/remix-ide-e2e/src/tests/terminal.test.ts +++ b/apps/remix-ide-e2e/src/tests/terminal.test.ts @@ -97,7 +97,7 @@ module.exports = { .switchEnvironment('vm-london') .click('*[data-id="terminalClearConsole"]') // clear the terminal .clickLaunchIcon('filePanel') - .click('*[data-id="treeViewDivtreeViewItem"]') // make sure we create the file at the root folder + .click('*[data-id="treeViewDivMenu"]') // make sure we create the file at the root folder .addFile('deployWithEthersJs.js', { content: deployWithEthersJs }) // .openFile('deployWithEthersJs.js') .pause(1000) @@ -562,7 +562,7 @@ describe("Storage", function () { contractName: 'StorageWithLib', sourceName: 'contracts/StorageWithLib.sol', abi: metadata.abi, - bytecode: '0x' + metadata.data.bytecode.object, + bytecode: metadata.data.bytecode.object, deployedBytecode: '0x' + metadata.data.deployedBytecode.object, linkReferences: metadata.data.bytecode.linkReferences, deployedLinkReferences: metadata.data.deployedBytecode.linkReferences, @@ -700,7 +700,7 @@ const scriptAutoExec = { contractName: 'Lib', sourceName: 'contracts/1_Storage.sol', abi: metadataLib.abi, - bytecode: '0x' + metadataLib.data.bytecode.object, + bytecode: metadataLib.data.bytecode.object, deployedBytecode: '0x' + metadataLib.data.deployedBytecode.object, linkReferences: metadataLib.data.bytecode.linkReferences, deployedLinkReferences: metadataLib.data.deployedBytecode.linkReferences, @@ -720,7 +720,7 @@ const scriptAutoExec = { contractName: 'Storage', sourceName: 'contracts/1_Storage.sol', abi: metadata.abi, - bytecode: '0x' + metadata.data.bytecode.object, + bytecode: metadata.data.bytecode.object, deployedBytecode: '0x' + metadata.data.deployedBytecode.object, linkReferences: metadata.data.bytecode.linkReferences, deployedLinkReferences: metadata.data.deployedBytecode.linkReferences, diff --git a/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts b/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts index a4ebf83709..c5fc0d8815 100644 --- a/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts +++ b/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts @@ -15,7 +15,7 @@ module.exports = { browser.testContracts('Untitled.sol', sources[0]['Untitled.sol'], ['TestContract']) .clickLaunchIcon('udapp') .selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite - .click('.udapp_contractActionsContainerSingle > button') + .click('.udapp_contractActionsContainerSingle > div') .clickInstance(0) .clickFunction('f - transact (not payable)') .testFunction('last', @@ -40,7 +40,7 @@ module.exports = { 'Test Complex Return Values #group1': function (browser: NightwatchBrowser) { browser.testContracts('returnValues.sol', sources[1]['returnValues.sol'], ['testReturnValues']) .clickLaunchIcon('udapp') - .click('.udapp_contractActionsContainerSingle > button') + .click('.udapp_contractActionsContainerSingle > div') .clickInstance(0) .clickFunction('retunValues1 - transact (not payable)') .testFunction('last', @@ -84,7 +84,7 @@ module.exports = { 'Test Complex Input Values #group2': function (browser: NightwatchBrowser) { browser.testContracts('inputValues.sol', sources[2]['inputValues.sol'], ['test']) .clickLaunchIcon('udapp') - .click('.udapp_contractActionsContainerSingle > button') + .click('.udapp_contractActionsContainerSingle > div') .clickInstance(0) .clickFunction('inputValue1 - transact (not payable)', { types: 'uint256 _u, int256 _i, string _str', values: '"2343242", "-4324324", "string _ string _ string _ string _ string _ string _ string _ string _ string _ string _"' }) .testFunction('last', @@ -129,7 +129,7 @@ module.exports = { browser.testContracts('eventFunctionInput.sol', sources[3]['eventFunctionInput.sol'], ['C']) .clickLaunchIcon('udapp') .selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite - .click('.udapp_contractActionsContainerSingle > button') + .click('.udapp_contractActionsContainerSingle > div') .clickInstance(0) .click('*[data-id="deployAndRunClearInstances"]') }, @@ -137,7 +137,7 @@ module.exports = { 'Should use scientific notation as parameters #group2': function (browser: NightwatchBrowser) { browser.testContracts('scientific_notation.sol', sources[8]['scientific_notation.sol'], ['test']) .clickLaunchIcon('udapp') - .click('.udapp_contractActionsContainerSingle > button') + .click('.udapp_contractActionsContainerSingle > div') .clickInstance(0) .clickFunction('inputValue1 - transact (not payable)', { types: 'uint256 _u, int256 _i', values: '"101e3", "-1.13e4"' }) .waitForElementContainsText('*[data-id="terminalJournal"]', '101000', 60000) @@ -154,7 +154,7 @@ module.exports = { browser.testContracts('customError.sol', sources[4]['customError.sol'], ['C']) .clickLaunchIcon('udapp') .selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite - .click('.udapp_contractActionsContainerSingle > button') + .click('.udapp_contractActionsContainerSingle > div') .clickInstance(0) .clickFunction('g - transact (not payable)') .journalLastChildIncludes('Error provided by the contract:') @@ -176,7 +176,7 @@ module.exports = { .clearTransactions() .switchEnvironment('vm-london') // switch to London fork .selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite - .click('.udapp_contractActionsContainerSingle > button') + .click('.udapp_contractActionsContainerSingle > div') .clickInstance(0) .clickFunction('g - transact (not payable)') .journalLastChildIncludes('Error provided by the contract:') @@ -194,7 +194,7 @@ module.exports = { 'Should Compile and Deploy a contract which define a custom error in a library, the error should be logged in the terminal #group3': function (browser: NightwatchBrowser) { browser.testContracts('customErrorLib.sol', sources[5]['customErrorLib.sol'], ['D']) .clickLaunchIcon('udapp') - .click('.udapp_contractActionsContainerSingle > button') + .click('.udapp_contractActionsContainerSingle > div') .clickInstance(1) .clickFunction('h - transact (not payable)') .journalLastChildIncludes('Error provided by the contract:') diff --git a/apps/remix-ide-e2e/src/tests/url.test.ts b/apps/remix-ide-e2e/src/tests/url.test.ts index d1d4ea084c..80405d41a8 100644 --- a/apps/remix-ide-e2e/src/tests/url.test.ts +++ b/apps/remix-ide-e2e/src/tests/url.test.ts @@ -10,11 +10,11 @@ const sources = [ 'myTokenV1.sol': { content: ` // SPDX-License-Identifier: MIT - pragma solidity ^0.8.4; + pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; - import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; contract MyToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable { @@ -23,9 +23,9 @@ const sources = [ _disableInitializers(); } - function initialize() initializer public { + function initialize(address initialOwner) initializer public { __ERC721_init("MyToken", "MTK"); - __Ownable_init(); + __Ownable_init(initialOwner); __UUPSUpgradeable_init(); } @@ -35,6 +35,7 @@ const sources = [ override {} } + ` } } @@ -166,7 +167,7 @@ module.exports = { .click('[data-id="compilerContainerCompileBtn"]') .clickLaunchIcon('filePanel') .isVisible({ - selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol"]', + selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"]', timeout: 120000, suppressNotFoundErrors: true }) @@ -174,7 +175,7 @@ module.exports = { .click('[data-id="compilerContainerCompileBtn"]') .clickLaunchIcon('filePanel') .isVisible({ - selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol"]', + selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"]', timeout: 120000, suppressNotFoundErrors: true }) @@ -182,7 +183,7 @@ module.exports = { .click('[data-id="compilerContainerCompileBtn"]') .clickLaunchIcon('filePanel') .waitForElementVisible({ - selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol"]', + selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"]', timeout: 120000, }) .clickLaunchIcon('solidity') diff --git a/apps/remix-ide-e2e/src/tests/workspace.test.ts b/apps/remix-ide-e2e/src/tests/workspace.test.ts index 09fe9057fe..1da1bba7b6 100644 --- a/apps/remix-ide-e2e/src/tests/workspace.test.ts +++ b/apps/remix-ide-e2e/src/tests/workspace.test.ts @@ -333,7 +333,7 @@ module.exports = { .click('*[data-id="treeViewLitreeViewItemcontracts/MyToken.sol"]') .pause(1000) .getEditorValue((content) => { - browser.assert.ok(content.indexOf(`contract MyToken is Initializable, ERC1155Upgradeable, OwnableUpgradeable, PausableUpgradeable, ERC1155BurnableUpgradeable, UUPSUpgradeable {`) !== -1, + browser.assert.ok(content.indexOf(`contract MyToken is Initializable, ERC1155Upgradeable, OwnableUpgradeable, ERC1155PausableUpgradeable, ERC1155BurnableUpgradeable, UUPSUpgradeable {`) !== -1, 'Incorrect content') }) .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts"]') diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index eacb27c9ee..4c356ca76f 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -1,105 +1,105 @@ // Merge custom command types with nightwatch types /* eslint-disable no-use-before-define */ -import { NightwatchBrowser } from 'nightwatch' // eslint-disable-line @typescript-eslint/no-unused-vars -export type callbackCheckVerifyCallReturnValue = (values: string[]) => { message: string, pass: boolean } +import {NightwatchBrowser} from 'nightwatch' // eslint-disable-line @typescript-eslint/no-unused-vars +export type callbackCheckVerifyCallReturnValue = (values: string[]) => {message: string; pass: boolean} declare module 'nightwatch' { - export interface NightwatchCustomCommands { - clickLaunchIcon(icon: string): NightwatchBrowser, - switchBrowserTab(index: number): NightwatchBrowser, - scrollAndClick(target: string): NightwatchBrowser, - scrollInto(target: string): NightwatchBrowser, - testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser, - setEditorValue(value: string, callback?: () => void): NightwatchBrowser, - addFile(name: string, content: NightwatchContractContent): NightwatchBrowser, - verifyContracts(compiledContractNames: string[], opts?: { wait: number, version?: string, runs?: string }): NightwatchBrowser, - selectAccount(account?: string): NightwatchBrowser, - clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser, - testFunction(txHash: string, expectedInput: NightwatchTestFunctionExpectedInput): NightwatchBrowser, - goToVMTraceStep(step: number, incr?: number): NightwatchBrowser, - checkVariableDebug(id: string, debugValue: NightwatchCheckVariableDebugValue): NightwatchBrowser, - addAtAddressInstance(address: string, isValidFormat: boolean, isValidChecksum: boolean, isAbi?: boolean): NightwatchBrowser, - modalFooterOKClick(id?: string): NightwatchBrowser, - clickInstance(index: number): NightwatchBrowser, - journalLastChildIncludes(val: string): NightwatchBrowser, - executeScriptInTerminal(script: string): NightwatchBrowser, - clearEditableContent(cssSelector: string): NightwatchBrowser, - journalChildIncludes(val: string, opts = { shouldHaveOnlyOneOccurence: boolean }): NightwatchBrowser, - debugTransaction(index: number): NightwatchBrowser, - checkElementStyle(cssSelector: string, styleProperty: string, expectedResult: string): NightwatchBrowser, - openFile(name: string): NightwatchBrowser, - refreshPage(): NightwatchBrowser, - verifyLoad(): NightwatchBrowser, - renamePath(path: string, newFileName: string, renamedPath: string): NightwatchBrowser, - rightClickCustom(cssSelector: string): NightwatchBrowser, - scrollToLine(line: number): NightwatchBrowser, - waitForElementContainsText(id: string, value: string, timeout?: number): NightwatchBrowser, - getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser, - modalFooterCancelClick(id?: string): NightwatchBrowser, - selectContract(contractName: string): NightwatchBrowser, - createContract(inputParams: string): NightwatchBrowser, - getAddressAtPosition(index: number, cb: (pos: string) => void): NightwatchBrowser, - testConstantFunction(address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser, - getEditorValue(callback: (content: string) => void): NightwatchBrowser, - getInstalledPlugins(cb: (plugins: string[]) => void): NightwatchBrowser, - verifyCallReturnValue(address: string, checks: string[] | callbackCheckVerifyCallReturnValue): NightwatchBrowser, - testEditorValue(testvalue: string): NightwatchBrowser, - removeFile(path: string, workspace: string): NightwatchBrowser, - switchBrowserWindow(url: string, windowName: string, cb: (browser: NightwatchBrowser, window?: NightwatchCallbackResult) => void): NightwatchBrowser, - setupMetamask(passphrase: string, password: string): NightwatchBrowser, - signMessage(msg: string, callback: (hash: { value: string }, signature: { value: string }) => void): NightwatchBrowser, - setSolidityCompilerVersion(version: string): NightwatchBrowser, - clickElementAtPosition(cssSelector: string, index: number, opt?: { forceSelectIfUnselected: boolean }): NightwatchBrowser, - notContainsText(cssSelector: string, text: string): NightwatchBrowser, - sendLowLevelTx(address: string, value: string, callData: string): NightwatchBrowser, - journalLastChild(val: string): NightwatchBrowser, - checkTerminalFilter(filter: string, test: string): NightwatchBrowser, - noWorkerErrorFor(version: string): NightwatchBrowser, - validateValueInput(selector: string, valueTosSet: string, expectedValue: string): NightwatchBrowser - checkAnnotations(type: string, line: number): NightwatchBrowser - checkAnnotationsNotPresent(type: string): NightwatchBrowser - getLastTransactionHash(callback: (hash: string) => void) - currentWorkspaceIs(name: string): NightwatchBrowser - addLocalPlugin(this: NightwatchBrowser, profile: Profile & LocationProfile & ExternalProfile): NightwatchBrowser - acceptAndRemember (this: NightwatchBrowser, remember: boolean, accept: boolean): NightwatchBrowser - clearConsole (this: NightwatchBrowser): NightwatchBrowser - clearTransactions (this: NightwatchBrowser): NightwatchBrowser - getBrowserLogs (this: NightwatchBrowser): NightwatchBrowser - currentSelectedFileIs (name: string): NightwatchBrowser, - switchWorkspace: (workspaceName: string) => NightwatchBrowser - switchEnvironment: (provider: string) => NightwatchBrowser - connectToExternalHttpProvider: (url: string, identifier: string) => NightwatchBrowser - } + export interface NightwatchCustomCommands { + clickLaunchIcon(icon: string): NightwatchBrowser + switchBrowserTab(index: number): NightwatchBrowser + scrollAndClick(target: string): NightwatchBrowser + scrollInto(target: string): NightwatchBrowser + testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser + setEditorValue(value: string, callback?: () => void): NightwatchBrowser + addFile(name: string, content: NightwatchContractContent): NightwatchBrowser + verifyContracts(compiledContractNames: string[], opts?: {wait: number; version?: string; runs?: string}): NightwatchBrowser + selectAccount(account?: string): NightwatchBrowser + clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser + testFunction(txHash: string, expectedInput: NightwatchTestFunctionExpectedInput): NightwatchBrowser + goToVMTraceStep(step: number, incr?: number): NightwatchBrowser + checkVariableDebug(id: string, debugValue: NightwatchCheckVariableDebugValue): NightwatchBrowser + addAtAddressInstance(address: string, isValidFormat: boolean, isValidChecksum: boolean, isAbi?: boolean): NightwatchBrowser + modalFooterOKClick(id?: string): NightwatchBrowser + clickInstance(index: number): NightwatchBrowser + journalLastChildIncludes(val: string): NightwatchBrowser + executeScriptInTerminal(script: string): NightwatchBrowser + clearEditableContent(cssSelector: string): NightwatchBrowser + journalChildIncludes(val: string, opts = {shouldHaveOnlyOneOccurence: boolean}): NightwatchBrowser + debugTransaction(index: number): NightwatchBrowser + checkElementStyle(cssSelector: string, styleProperty: string, expectedResult: string): NightwatchBrowser + openFile(name: string): NightwatchBrowser + refreshPage(): NightwatchBrowser + verifyLoad(): NightwatchBrowser + renamePath(path: string, newFileName: string, renamedPath: string): NightwatchBrowser + rightClickCustom(cssSelector: string): NightwatchBrowser + scrollToLine(line: number): NightwatchBrowser + waitForElementContainsText(id: string, value: string, timeout?: number): NightwatchBrowser + getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser + modalFooterCancelClick(id?: string): NightwatchBrowser + selectContract(contractName: string): NightwatchBrowser + createContract(inputParams: string): NightwatchBrowser + getAddressAtPosition(index: number, cb: (pos: string) => void): NightwatchBrowser + testConstantFunction(address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser + getEditorValue(callback: (content: string) => void): NightwatchBrowser + getInstalledPlugins(cb: (plugins: string[]) => void): NightwatchBrowser + verifyCallReturnValue(address: string, checks: string[] | callbackCheckVerifyCallReturnValue): NightwatchBrowser + testEditorValue(testvalue: string): NightwatchBrowser + removeFile(path: string, workspace: string): NightwatchBrowser + switchBrowserWindow(url: string, windowName: string, cb: (browser: NightwatchBrowser, window?: NightwatchCallbackResult) => void): NightwatchBrowser + setupMetamask(passphrase: string, password: string): NightwatchBrowser + signMessage(msg: string, callback: (hash: {value: string}, signature: {value: string}) => void): NightwatchBrowser + setSolidityCompilerVersion(version: string): NightwatchBrowser + clickElementAtPosition(cssSelector: string, index: number, opt?: {forceSelectIfUnselected: boolean}): NightwatchBrowser + notContainsText(cssSelector: string, text: string): NightwatchBrowser + sendLowLevelTx(address: string, value: string, callData: string): NightwatchBrowser + journalLastChild(val: string): NightwatchBrowser + checkTerminalFilter(filter: string, test: string): NightwatchBrowser + noWorkerErrorFor(version: string): NightwatchBrowser + validateValueInput(selector: string, valueTosSet: string, expectedValue: string): NightwatchBrowser + checkAnnotations(type: string): NightwatchBrowser + checkAnnotationsNotPresent(type: string): NightwatchBrowser + getLastTransactionHash(callback: (hash: string) => void) + currentWorkspaceIs(name: string): NightwatchBrowser + addLocalPlugin(this: NightwatchBrowser, profile: Profile & LocationProfile & ExternalProfile): NightwatchBrowser + acceptAndRemember(this: NightwatchBrowser, remember: boolean, accept: boolean): NightwatchBrowser + clearConsole(this: NightwatchBrowser): NightwatchBrowser + clearTransactions(this: NightwatchBrowser): NightwatchBrowser + getBrowserLogs(this: NightwatchBrowser): NightwatchBrowser + currentSelectedFileIs(name: string): NightwatchBrowser + switchWorkspace: (workspaceName: string) => NightwatchBrowser + switchEnvironment: (provider: string) => NightwatchBrowser + connectToExternalHttpProvider: (url: string, identifier: string) => NightwatchBrowser + } - export interface NightwatchBrowser { - api: this, - emit: (status: string) => void, - fullscreenWindow: (result?: any) => this, - keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void): NightwatchBrowser, - sendKeys: (selector: string, inputValue: string | string[], callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void) => NightwatchBrowser - } + export interface NightwatchBrowser { + api: this + emit: (status: string) => void + fullscreenWindow: (result?: any) => this + keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void): NightwatchBrowser + sendKeys: (selector: string, inputValue: string | string[], callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void) => NightwatchBrowser + } - export interface NightwatchAPI { - keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void): NightwatchAPI - } + export interface NightwatchAPI { + keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void): NightwatchAPI + } - export interface NightwatchContractContent { - content: string; - } + export interface NightwatchContractContent { + content: string + } - export interface NightwatchClickFunctionExpectedInput { - types: string, - values: string - } + export interface NightwatchClickFunctionExpectedInput { + types: string + values: string + } - export interface NightwatchTestFunctionExpectedInput { - [key: string]: any - } + export interface NightwatchTestFunctionExpectedInput { + [key: string]: any + } - export interface NightwatchTestConstantFunctionExpectedInput { - types: string, - values: string - } + export interface NightwatchTestConstantFunctionExpectedInput { + types: string + values: string + } - export type NightwatchCheckVariableDebugValue = NightwatchTestFunctionExpectedInput + export type NightwatchCheckVariableDebugValue = NightwatchTestFunctionExpectedInput } diff --git a/apps/remix-ide-e2e/yarn.lock b/apps/remix-ide-e2e/yarn.lock index d733532ba3..b9811ee8ee 100644 --- a/apps/remix-ide-e2e/yarn.lock +++ b/apps/remix-ide-e2e/yarn.lock @@ -14,28 +14,29 @@ pathval "1.1.1" type-detect "4.0.8" -"@openzeppelin/contracts-upgradeable@^4.8.3": - version "4.8.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.8.3.tgz#6b076a7b751811b90fe3a172a7faeaa603e13a3f" - integrity sha512-SXDRl7HKpl2WDoJpn7CK/M9U4Z8gNXDHHChAKh0Iz+Wew3wu6CmFYBeie3je8V0GSXZAIYYwUktSrnW/kwVPtg== +"@openzeppelin/contracts-upgradeable@^4.9.2": + version "4.9.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.3.tgz#ff17a80fb945f5102571f8efecb5ce5915cc4811" + integrity sha512-jjaHAVRMrE4UuZNfDwjlLGDxTHWIOwTJS2ldnc278a0gevfXfPr8hxKEVBGFBE96kl2G3VHDZhUimw/+G3TG2A== -"@openzeppelin/contracts@^4.8.3": - version "4.8.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.8.3.tgz#cbef3146bfc570849405f59cba18235da95a252a" - integrity sha512-bQHV8R9Me8IaJoJ2vPG4rXcL7seB7YVuskr4f+f5RyOStSZetwzkWtoqDMl5erkBJy0lDRUnIR2WIkPiC0GJlg== +"@openzeppelin/contracts@^4.9.2": + version "4.9.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.3.tgz#00d7a8cf35a475b160b3f0293a6403c511099364" + integrity sha512-He3LieZ1pP2TNt5JbkPA4PNT9WC3gOTOlDcFGJW4Le4QKqwmiNJCRt44APfxMxvq7OugU/cqYuPcSBzOw38DAg== "@openzeppelin/upgrades-core@^1.22.0": - version "1.24.1" - resolved "https://registry.yarnpkg.com/@openzeppelin/upgrades-core/-/upgrades-core-1.24.1.tgz#2b0c877f2a404d3384bacd4ce1e29bee14a14ea8" - integrity sha512-QhdIQDUykJ3vQauB6CheV7vk4zgn0e1iY+IDg7r1KqpA1m2bqIGjQCpzidW33K4bZc9zdJSPx2/Z6Um5KxCB7A== + version "1.28.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/upgrades-core/-/upgrades-core-1.28.0.tgz#19405f272dc09e766c756d9d149cbd680168aef7" + integrity sha512-8RKlyg98Adv+46GxDaR0awL3R8bVCcQ27DcSEwrgWOp6siHh8sZg4a2l+2dhPl1510S6uBfhHSydMH5VX2BV5g== dependencies: - cbor "^8.0.0" + cbor "^9.0.0" chalk "^4.1.0" - compare-versions "^5.0.0" + compare-versions "^6.0.0" debug "^4.1.1" ethereumjs-util "^7.0.3" + minimist "^1.2.7" proper-lockfile "^4.1.1" - solidity-ast "^0.4.15" + solidity-ast "^0.4.26" "@openzeppelin/wizard@^0.1.1": version "0.1.1" @@ -44,13 +45,26 @@ dependencies: array.prototype.flatmap "^1.2.4" +"@puppeteer/browsers@^1.5.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.6.0.tgz#d52413a7039e40a5ef72fb13fb6505fd87ce842e" + integrity sha512-R2ib8j329427jtKB/qlz0MJbwfJE/6I8ocJLiajsRqJ2PPI8DbjiNzC3lQZeISXEcjOBVhbG2RafN8SlHdcT+A== + dependencies: + debug "4.3.4" + extract-zip "2.0.1" + progress "2.0.3" + proxy-agent "6.3.0" + tar-fs "3.0.4" + unbzip2-stream "1.4.3" + yargs "17.7.1" + "@remix-project/remixd@../../dist/libs/remixd": - version "0.6.12" + version "0.6.16" dependencies: - "@remixproject/plugin" "^0.3.11" - "@remixproject/plugin-api" "^0.3.11" - "@remixproject/plugin-utils" "^0.3.11" - "@remixproject/plugin-ws" "^0.3.11" + "@remixproject/plugin" "0.3.33" + "@remixproject/plugin-api" "0.3.33" + "@remixproject/plugin-utils" "0.3.33" + "@remixproject/plugin-ws" "0.3.33" axios "1.1.2" chokidar "^2.1.8" commander "^9.4.1" @@ -60,36 +74,36 @@ semver "^6.3.0" ws "^7.3.0" -"@remixproject/plugin-api@0.3.31", "@remixproject/plugin-api@^0.3.11": - version "0.3.31" - resolved "https://registry.yarnpkg.com/@remixproject/plugin-api/-/plugin-api-0.3.31.tgz#86e7c458c58ff200bd927fd3d642877f4b5a0013" - integrity sha512-LOJRHxORNp7zW8k7//DQz5aZ7eqB7TwhYXrvzqvaryDTvtvJGWrlTHg81hzALynaxZKEWneohxjUxKvGp/eA4g== +"@remixproject/plugin-api@0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@remixproject/plugin-api/-/plugin-api-0.3.33.tgz#29699f980ea00bebf720961cc0e78887e03903ec" + integrity sha512-fBEbRr6/mgQdfNdRqYQL3yewsPfTxV41F509CngbD6YdY5YKBihJhfGFHbd2rKSyXOgBiHIbe0SsV3OXpFdWnw== dependencies: - "@remixproject/plugin-utils" "0.3.31" + "@remixproject/plugin-utils" "0.3.33" -"@remixproject/plugin-utils@0.3.31", "@remixproject/plugin-utils@^0.3.11": - version "0.3.31" - resolved "https://registry.yarnpkg.com/@remixproject/plugin-utils/-/plugin-utils-0.3.31.tgz#80771e00c1a1b776432abb17b1f4b2e25600d4f6" - integrity sha512-OOAjoSd+ErBMrcNQEh80NU3BjJ9fHXuftRfy5Ul9aGXN3b1LJSNVvfrG+FxX6lpyaAK5JBj+aB9pgFozgb2wlw== +"@remixproject/plugin-utils@0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@remixproject/plugin-utils/-/plugin-utils-0.3.33.tgz#7b697403031598276baaf16bb82d6c62062053fc" + integrity sha512-cAo21ot4/G5BkN8ypDwg8MMCrEmLdXwMd3lQZUeB5enPC3KxmzQz71+OgEYl718Hwy+GtHaLq17FEXCHC5YV9w== dependencies: tslib "2.0.1" -"@remixproject/plugin-ws@^0.3.11": - version "0.3.31" - resolved "https://registry.yarnpkg.com/@remixproject/plugin-ws/-/plugin-ws-0.3.31.tgz#a2bb415cc32a5b036b9b3759520088b8ceaa0d5a" - integrity sha512-Z4G6vkGxxCP+ibGNHAvNaFjYE4hbsazOEL50pMnda6LZNci9akMSiI/1MIZscVSMU8l2sYOoNUsWvLfLkIkYKQ== +"@remixproject/plugin-ws@0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@remixproject/plugin-ws/-/plugin-ws-0.3.33.tgz#98a003e83ffafb5a7a35ca4e8c59d849ecb017cf" + integrity sha512-Zkp8MK8jxnNm3uruu0dF8vqeh90JsLXttJP4LZF0HaStRRK4d2XG6CgE5mBiC2J4uTEwGP26H/vmqi+POBPTEg== dependencies: - "@remixproject/plugin" "0.3.31" - "@remixproject/plugin-api" "0.3.31" - "@remixproject/plugin-utils" "0.3.31" + "@remixproject/plugin" "0.3.33" + "@remixproject/plugin-api" "0.3.33" + "@remixproject/plugin-utils" "0.3.33" -"@remixproject/plugin@0.3.31", "@remixproject/plugin@^0.3.11": - version "0.3.31" - resolved "https://registry.yarnpkg.com/@remixproject/plugin/-/plugin-0.3.31.tgz#b6c6b58d2c7964e37024eeca4819c70ece1f3953" - integrity sha512-9ntMU9CzStloahm/wXt4V8n64ERgJzY5nG0bzQfjnI12knrdTmUo+LC42M2xaTBDDP9CzMPdqClg7XhhRLzohA== +"@remixproject/plugin@0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@remixproject/plugin/-/plugin-0.3.33.tgz#2939cdb6a1231743d7f00c10f5ea47eddd49b602" + integrity sha512-ia6LevsWYPkcRwOBl3umA2fPCgYt2TmB437Pafs9BE6fD9judEvlvEqXjBy9GLBsZzZWSiyYenOnW8HIiwqfMA== dependencies: - "@remixproject/plugin-api" "0.3.31" - "@remixproject/plugin-utils" "0.3.31" + "@remixproject/plugin-api" "0.3.33" + "@remixproject/plugin-utils" "0.3.33" events "3.2.0" "@sindresorhus/is@^0.14.0": @@ -116,6 +130,11 @@ dependencies: defer-to-connect "^2.0.0" +"@tootallnate/quickjs-emscripten@^0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" + integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== + "@types/bn.js@^4.11.3": version "4.11.6" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" @@ -153,9 +172,9 @@ "@types/node" "*" "@types/node@*": - version "18.14.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.6.tgz#ae1973dd2b1eeb1825695bb11ebfb746d27e3e93" - integrity sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA== + version "20.5.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.0.tgz#7fc8636d5f1aaa3b21e6245e97d56b7f56702313" + integrity sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q== "@types/pbkdf2@^3.0.0": version "3.1.0" @@ -178,17 +197,24 @@ dependencies: "@types/node" "*" +"@types/yauzl@^2.9.1": + version "2.10.0" + resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599" + integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw== + dependencies: + "@types/node" "*" + "@ungap/promise-all-settled@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== +agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" + integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== dependencies: - event-target-shim "^5.0.0" + debug "^4.3.4" ansi-align@^3.0.0: version "3.0.1" @@ -269,6 +295,14 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -284,6 +318,18 @@ array.prototype.flatmap@^1.2.4: es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" +arraybuffer.prototype.slice@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz#9b5ea3868a6eebc30273da577eb888381c0044bb" + integrity sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + assertion-error@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" @@ -294,6 +340,13 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== +ast-types@^0.13.4: + version "0.13.4" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" + integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== + dependencies: + tslib "^2.0.1" + async-each@^1.0.1: version "1.0.6" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.6.tgz#52f1d9403818c179b7561e11a5d1b77eb2160e77" @@ -327,9 +380,9 @@ available-typed-arrays@^1.0.5: integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== axe-core@^4.4.3: - version "4.6.3" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.6.3.tgz#fc0db6fdb65cc7a80ccf85286d91d64ababa3ece" - integrity sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg== + version "4.7.2" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.2.tgz#040a7342b20765cb18bb50b628394c21bccc17a0" + integrity sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g== axios@1.1.2: version "1.1.2" @@ -340,10 +393,19 @@ axios@1.1.2: form-data "^4.0.0" proxy-from-env "^1.1.0" -b4a@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.1.tgz#9effac93a469a868d024e16fd77162c653544cbd" - integrity sha512-AsKjNhz72yxteo/0EtQEiwkMUgk/tGmycXlbG4g3Ard2/ULtNLUykGOkeK0egmN27h0xMAhb76jYccW+XTBExA== +axios@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" + integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +b4a@^1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9" + integrity sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw== balanced-match@^1.0.0: version "1.0.2" @@ -382,6 +444,11 @@ basic-auth@^2.0.1: dependencies: safe-buffer "5.1.2" +basic-ftp@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/basic-ftp/-/basic-ftp-5.0.3.tgz#b14c0fe8111ce001ec913686434fe0c2fb461228" + integrity sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g== + binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" @@ -408,15 +475,6 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -bl@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-6.0.0.tgz#1f10c18a3289d412053add35cca09019075cff2d" - integrity sha512-Ik9BVIMdcWzSOCpzDv2XpQ4rJ4oZBuk3ck6MgiOv0EopdgtohN2uSCrrLlkH1Jf0KnpZZMBA3D0bUMbCdj/jgA== - dependencies: - buffer "^6.0.3" - inherits "^2.0.4" - readable-stream "^4.2.0" - blakejs@^1.1.0: version "1.2.1" resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" @@ -555,7 +613,7 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== -buffer@^5.5.0: +buffer@^5.2.1, buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -563,14 +621,6 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -605,9 +655,9 @@ cacheable-request@^6.0.0: responselike "^1.0.2" cacheable-request@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" - integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== + version "7.0.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" + integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== dependencies: clone-response "^1.0.2" get-stream "^5.1.0" @@ -635,10 +685,10 @@ camelcase@^6.0.0, camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -cbor@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/cbor/-/cbor-8.1.0.tgz#cfc56437e770b73417a2ecbfc9caf6b771af60d5" - integrity sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg== +cbor@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-9.0.1.tgz#b16e393d4948d44758cd54ac6151379d443b37ae" + integrity sha512-/TQOWyamDxvVIv+DY9cOLNuABkoyz8K/F3QE56539pGVYohx0+MEA1f4lChFTX79dBTBS7R1PF6ovH7G+VtBfQ== dependencies: nofilter "^3.1.0" @@ -732,9 +782,9 @@ cli-cursor@^3.1.0: restore-cursor "^3.1.0" cli-spinners@^2.5.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a" - integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== + version "2.9.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.0.tgz#5881d0ad96381e117bbe07ad91f2008fe6ffd8db" + integrity sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g== cliui@^5.0.0: version "5.0.0" @@ -754,6 +804,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + clone-response@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" @@ -806,19 +865,19 @@ combined-stream@^1.0.8: delayed-stream "~1.0.0" commander@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.0.tgz#71797971162cd3cf65f0b9d24eb28f8d303acdf1" - integrity sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA== + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== commander@^9.4.1: version "9.5.0" resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== -compare-versions@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-5.0.3.tgz#a9b34fea217472650ef4a2651d905f42c28ebfd7" - integrity sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A== +compare-versions@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.0.tgz#3f2131e3ae93577df111dba133e6db876ffe127a" + integrity sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg== component-emitter@^1.2.1: version "1.3.0" @@ -888,6 +947,18 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +data-uri-to-buffer@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz#db89a9e279c2ffe74f50637a59a32fb23b3e4d7c" + integrity sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg== + +debug@4, debug@4.3.4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debug@4.3.3: version "4.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" @@ -909,13 +980,6 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.1, debug@^4.3.1: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -991,7 +1055,7 @@ define-lazy-prop@^2.0.0: resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== -define-properties@^1.1.3, define-properties@^1.1.4: +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== @@ -1021,6 +1085,15 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" +degenerator@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-5.0.1.tgz#9403bf297c6dad9a1ece409b37db27954f91f2f5" + integrity sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ== + dependencies: + ast-types "^0.13.4" + escodegen "^2.1.0" + esprima "^4.0.1" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -1094,17 +1167,18 @@ envinfo@7.8.1: integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.21.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6" - integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg== + version "1.22.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc" + integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw== dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.1" available-typed-arrays "^1.0.5" call-bind "^1.0.2" es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" - function-bind "^1.1.1" function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.1" get-symbol-description "^1.0.0" globalthis "^1.0.3" gopd "^1.0.1" @@ -1112,8 +1186,8 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: has-property-descriptors "^1.0.0" has-proto "^1.0.1" has-symbols "^1.0.3" - internal-slot "^1.0.4" - is-array-buffer "^3.0.1" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" is-callable "^1.2.7" is-negative-zero "^2.0.2" is-regex "^1.1.4" @@ -1121,16 +1195,21 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: is-string "^1.0.7" is-typed-array "^1.1.10" is-weakref "^1.0.2" - object-inspect "^1.12.2" + object-inspect "^1.12.3" object-keys "^1.1.1" object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" + regexp.prototype.flags "^1.5.0" + safe-array-concat "^1.0.0" safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.7" string.prototype.trimend "^1.0.6" string.prototype.trimstart "^1.0.6" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" typed-array-length "^1.0.4" unbox-primitive "^1.0.2" - which-typed-array "^1.1.9" + which-typed-array "^1.1.10" es-set-tostringtag@^2.0.1: version "2.0.1" @@ -1167,6 +1246,32 @@ escape-string-regexp@4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +escodegen@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" + integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionalDependencies: + source-map "~0.6.1" + +esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + ethereum-cryptography@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" @@ -1220,11 +1325,6 @@ ethjs-util@0.1.6: is-hex-prefixed "1.0.0" strip-hex-prefix "1.0.0" -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -1235,11 +1335,6 @@ events@3.2.0: resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== -events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" @@ -1303,10 +1398,21 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -fast-fifo@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.1.0.tgz#17d1a3646880b9891dfa0c54e69c5fef33cad779" - integrity sha512-Kl29QoNbNvn4nhDsLYjyIAaIqaJB6rBx5p3sL9VjaefJ+eMFBWVZiaoguaoZfzEKr5RhAti0UgM8703akGPJ6g== +extract-zip@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== + dependencies: + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" + +fast-fifo@^1.1.0, fast-fifo@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.0.tgz#03e381bcbfb29932d7c3afde6e15e83e05ab4d8b" + integrity sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw== fd-slicer@~1.1.0: version "1.1.0" @@ -1320,7 +1426,7 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== -filelist@^1.0.1: +filelist@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== @@ -1415,6 +1521,15 @@ fs-extra@^3.0.1: jsonfile "^3.0.0" universalify "^0.1.0" +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1448,7 +1563,7 @@ function.prototype.name@^1.1.5: es-abstract "^1.19.0" functions-have-names "^1.2.2" -functions-have-names@^1.2.2: +functions-have-names@^1.2.2, functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== @@ -1472,13 +1587,14 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" - integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== dependencies: function-bind "^1.1.1" has "^1.0.3" + has-proto "^1.0.1" has-symbols "^1.0.3" get-stream@^4.0.0, get-stream@^4.1.0: @@ -1503,6 +1619,16 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" +get-uri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.1.tgz#cff2ba8d456c3513a04b70c45de4dbcca5b1527c" + integrity sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q== + dependencies: + basic-ftp "^5.0.2" + data-uri-to-buffer "^5.0.1" + debug "^4.3.4" + fs-extra "^8.1.0" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -1596,9 +1722,9 @@ got@^9.6.0: url-parse-lax "^3.0.0" graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== growl@1.10.5: version "1.10.5" @@ -1720,6 +1846,14 @@ http-cache-semantics@^4.0.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== +http-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673" + integrity sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + http-proxy@^1.18.1: version "1.18.1" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" @@ -1756,6 +1890,14 @@ http2-wrapper@^1.0.0-beta.5.2: quick-lru "^5.1.1" resolve-alpn "^1.0.0" +https-proxy-agent@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz#0277e28f13a07d45c663633841e20a40aaafe0ab" + integrity sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ== + dependencies: + agent-base "^7.0.2" + debug "4" + iconv-lite@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -1763,7 +1905,7 @@ iconv-lite@0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.13, ieee754@^1.2.1: +ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -1791,7 +1933,7 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -internal-slot@^1.0.4: +internal-slot@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== @@ -1805,6 +1947,16 @@ invert-kv@^2.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== +ip@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48" + integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== + +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -1827,7 +1979,7 @@ is-arguments@^1.0.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-array-buffer@^3.0.1: +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== @@ -2046,15 +2198,11 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: has-symbols "^1.0.2" is-typed-array@^1.1.10, is-typed-array@^1.1.9: - version "1.1.10" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" + which-typed-array "^1.1.11" is-unicode-supported@^0.1.0: version "0.1.0" @@ -2085,6 +2233,11 @@ isarray@1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isbinaryfile@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" @@ -2110,14 +2263,14 @@ isobject@^3.0.0, isobject@^3.0.1: integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== jake@^10.8.5: - version "10.8.5" - resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.5.tgz#f2183d2c59382cb274226034543b9c03b8164c46" - integrity sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw== + version "10.8.7" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.7.tgz#63a32821177940c33f356e0ba44ff9d34e1c7d8f" + integrity sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w== dependencies: async "^3.2.3" chalk "^4.0.2" - filelist "^1.0.1" - minimatch "^3.0.4" + filelist "^1.0.4" + minimatch "^3.1.2" js-yaml@4.1.0: version "4.1.0" @@ -2143,6 +2296,13 @@ jsonfile@^3.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -2179,9 +2339,9 @@ keyv@^3.0.0: json-buffer "3.0.0" keyv@^4.0.0: - version "4.5.2" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56" - integrity sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g== + version "4.5.3" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25" + integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== dependencies: json-buffer "3.0.1" @@ -2385,6 +2545,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@^7.14.1: + version "7.18.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + map-age-cleaner@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" @@ -2483,7 +2648,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.1.1: +minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -2509,7 +2674,7 @@ minimist@1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -2522,6 +2687,11 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@^0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -2530,9 +2700,9 @@ mkdirp@^0.5.6: minimist "^1.2.6" mkdirp@^2.1.3: - version "2.1.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.4.tgz#34faf1f2a1b4cc9a65a84e2979087211da608d11" - integrity sha512-Cy9cV4pRSl1o10i1dURTuRt4T04l0DkS1WZrT+Jir886OqOVkSv4FbOA7pgjhS8kEUrmm4kCRvv5var2iOCxpA== + version "2.1.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" + integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== mkpath@1.0.0: version "1.0.0" @@ -2611,6 +2781,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +netmask@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" + integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -2710,7 +2885,7 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.12.2, object-inspect@^1.9.0: +object-inspect@^1.12.3, object-inspect@^1.9.0: version "1.12.3" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== @@ -2862,6 +3037,29 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pac-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.0.tgz#db42120c64292685dafaf2bd921e223c56bfb13b" + integrity sha512-t4tRAMx0uphnZrio0S0Jw9zg3oDbz1zVhQ/Vy18FjLfP1XOLNUEjaVxYCYRI6NS+BsMBXKIzV6cTLOkO9AtywA== + dependencies: + "@tootallnate/quickjs-emscripten" "^0.23.0" + agent-base "^7.0.2" + debug "^4.3.4" + get-uri "^6.0.1" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.0" + pac-resolver "^7.0.0" + socks-proxy-agent "^8.0.1" + +pac-resolver@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-7.0.0.tgz#79376f1ca26baf245b96b34c339d79bff25e900c" + integrity sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg== + dependencies: + degenerator "^5.0.0" + ip "^1.1.8" + netmask "^2.0.2" + package-json@^6.3.0: version "6.5.0" resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" @@ -2962,11 +3160,6 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - progress@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -2981,6 +3174,20 @@ proper-lockfile@^4.1.1: retry "^0.12.0" signal-exit "^3.0.2" +proxy-agent@6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.3.0.tgz#72f7bb20eb06049db79f7f86c49342c34f9ba08d" + integrity sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og== + dependencies: + agent-base "^7.0.2" + debug "^4.3.4" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.0" + lru-cache "^7.14.1" + pac-proxy-agent "^7.0.0" + proxy-from-env "^1.1.0" + socks-proxy-agent "^8.0.1" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -2995,9 +3202,9 @@ pump@^3.0.0: once "^1.3.1" qs@^6.4.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + version "6.11.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== dependencies: side-channel "^1.0.4" @@ -3042,24 +3249,14 @@ readable-stream@^2.0.2, readable-stream@~2.3.6: util-deprecate "~1.0.1" readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.1.tgz#f9f9b5f536920253b3d26e7660e7da4ccff9bb62" - integrity sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ== + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.3.0.tgz#0914d0c72db03b316c9733bb3461d64a3cc50cba" - integrity sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ== - dependencies: - abort-controller "^3.0.0" - buffer "^6.0.3" - events "^3.3.0" - process "^0.11.10" - readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -3084,14 +3281,14 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" + integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" + define-properties "^1.2.0" + functions-have-names "^1.2.3" registry-auth-token@^4.0.0: version "4.2.2" @@ -3201,6 +3398,16 @@ rlp@^2.2.3, rlp@^2.2.4: dependencies: bn.js "^5.2.0" +safe-array-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.0.tgz#2064223cba3c08d2ee05148eedbc563cd6d84060" + integrity sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + has-symbols "^1.0.3" + isarray "^2.0.5" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -3251,11 +3458,13 @@ secure-compare@3.0.1: resolved "https://registry.yarnpkg.com/secure-compare/-/secure-compare-3.0.1.tgz#f1a0329b308b221fae37b9974f3d578d0ca999e3" integrity sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw== -selenium-standalone@^8.2.3: - version "8.3.0" - resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-8.3.0.tgz#effe900ffb764f2b9db29d3b2008ea68f289e328" - integrity sha512-cQVWQGxumvPnyzFNtzFtBfDCbqBsdEnwiOwRyrAzeUqf5ltAp3Z3+2f6asSFbLUQJs2sFuF6PsEyNA+eOzXKxg== +selenium-standalone@^9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-9.0.3.tgz#2e484c5412d28e60f4b8837305b2f573f28e8147" + integrity sha512-uv2Cx+VVwVSxBoUdA+fjiyXPNyP9fFZf3sl8hokz+KetNNMXZw6s+fxkUNvmZKL0jdvAI/fnHf+xjMCo/0NiKQ== dependencies: + "@puppeteer/browsers" "^1.5.0" + axios "^1.4.0" commander "^10.0.0" cross-spawn "^7.0.3" debug "^4.3.1" @@ -3267,7 +3476,7 @@ selenium-standalone@^8.2.3: minimist "^1.2.5" mkdirp "^2.1.3" progress "2.0.3" - tar-stream "3.0.0" + tar-stream "3.1.6" which "^2.0.2" yauzl "^2.10.0" @@ -3288,14 +3497,14 @@ semver@7.3.5: lru-cache "^6.0.0" semver@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== semver@^6.2.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== serialize-javascript@6.0.0: version "6.0.0" @@ -3370,6 +3579,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -3400,10 +3614,27 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -solidity-ast@^0.4.15: - version "0.4.46" - resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.46.tgz#d0745172dced937741d07464043564e35b147c59" - integrity sha512-MlPZQfPhjWXqh7YxWcBGDXaPZIfMYCOHYoLEhGDWulNwEPIQQZuB7mA9eP17CU0jY/bGR4avCEUVVpvHtT2gbA== +socks-proxy-agent@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz#ffc5859a66dac89b0c4dab90253b96705f3e7120" + integrity sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ== + dependencies: + agent-base "^7.0.1" + debug "^4.3.4" + socks "^2.7.1" + +socks@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" + integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== + dependencies: + ip "^2.0.0" + smart-buffer "^4.2.0" + +solidity-ast@^0.4.26: + version "0.4.49" + resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.49.tgz#ecba89d10c0067845b7848c3a3e8cc61a4fc5b82" + integrity sha512-Pr5sCAj1SFqzwFZw1HPKSq0PehlQNdM8GwKyAVYh2DOn7/cCK8LUKD1HeHnKtTgBW7hi9h4nnnan7hpAg5RhWQ== source-map-resolve@^0.5.0: version "0.5.3" @@ -3434,7 +3665,7 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== -source-map@^0.6.0: +source-map@^0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -3461,10 +3692,10 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -streamx@^2.12.5: - version "2.13.2" - resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.13.2.tgz#9de43569a1cd54980d128673b3c1429b79afff1c" - integrity sha512-+TWqixPhGDXEG9L/XczSbhfkmwAtGs3BJX5QNU6cvno+pOLKeszByWcnaTu6dg8efsTYqR8ZZuXWHhZfgrxMvA== +streamx@^2.15.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6" + integrity sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA== dependencies: fast-fifo "^1.1.0" queue-tick "^1.0.1" @@ -3478,7 +3709,7 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -3487,6 +3718,15 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2 is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string.prototype.trim@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + string.prototype.trimend@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" @@ -3569,14 +3809,28 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -tar-stream@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.0.0.tgz#43de9f0e8d1bccc0036dbe2731260ca7668406b6" - integrity sha512-O6OfUKBbQOqAhh6owTWmA730J/yZCYcpmZ1DBj2YX51ZQrt7d7NgzrR+CnO9wP6nt/viWZW2XeXLavX3/ZEbEg== +tar-fs@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.4.tgz#a21dc60a2d5d9f55e0089ccd78124f1d3771dbbf" + integrity sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w== + dependencies: + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^3.1.5" + +tar-stream@3.1.6, tar-stream@^3.1.5: + version "3.1.6" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.6.tgz#6520607b55a06f4a2e2e04db360ba7d338cc5bab" + integrity sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg== dependencies: - b4a "^1.6.1" - bl "^6.0.0" - streamx "^2.12.5" + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" + +through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== tmp@^0.2.1: version "0.2.1" @@ -3632,6 +3886,11 @@ tslib@2.0.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e" integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== +tslib@^2.0.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" + integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== + type-detect@4.0.8, type-detect@^4.0.0: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" @@ -3647,6 +3906,36 @@ type-fest@^0.7.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + typed-array-length@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" @@ -3666,6 +3955,14 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +unbzip2-stream@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" + integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== + dependencies: + buffer "^5.2.1" + through "^2.3.8" + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -3764,21 +4061,20 @@ which-boxed-primitive@^1.0.2: is-symbol "^1.0.3" which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== -which-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== +which-typed-array@^1.1.10, which-typed-array@^1.1.11: + version "1.1.11" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" + integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== dependencies: available-typed-arrays "^1.0.5" call-bind "^1.0.2" for-each "^0.3.3" gopd "^1.0.1" has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" which@2.0.2, which@^2.0.1, which@^2.0.2: version "2.0.2" @@ -3830,9 +4126,9 @@ wrappy@1: integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== ws@>=8.7.0: - version "8.12.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.1.tgz#c51e583d79140b5e42e39be48c934131942d4a8f" - integrity sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew== + version "8.13.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" + integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== ws@^7.3.0: version "7.5.9" @@ -3872,6 +4168,11 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs-unparser@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" @@ -3912,6 +4213,19 @@ yargs@16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@17.7.1: + version "17.7.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" + integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yauzl@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" diff --git a/apps/remix-ide/background.js b/apps/remix-ide/background.js index 8b9269f940..5bffa0da9e 100644 --- a/apps/remix-ide/background.js +++ b/apps/remix-ide/background.js @@ -2,9 +2,9 @@ 'use strict' chrome.browserAction.onClicked.addListener(function (tab) { - chrome.storage.sync.set({ 'chrome-app-sync': true }) + chrome.storage.sync.set({'chrome-app-sync': true}) - chrome.tabs.create({ 'url': chrome.extension.getURL('index.html') }, function (tab) { + chrome.tabs.create({url: chrome.extension.getURL('index.html')}, function (tab) { // tab opened }) }) diff --git a/apps/remix-ide/ci/download_e2e_assets.js b/apps/remix-ide/ci/download_e2e_assets.js index 51c161b895..99a089174f 100644 --- a/apps/remix-ide/ci/download_e2e_assets.js +++ b/apps/remix-ide/ci/download_e2e_assets.js @@ -5,8 +5,8 @@ const { exit } = require('process'); const child = child_process.spawnSync('grep -r --include="*.json" --include="*.ts" --include="*.tsx" "+commit" apps/**/* libs/**/*', [], { encoding: 'utf8', cwd: process.cwd(), shell: true }); if (child.error) { - console.log("ERROR: ", child); - exit(1); + console.log("ERROR: ", child); + exit(1); } @@ -15,63 +15,63 @@ let soljson =[]; const quotedVersionsRegex = /['"v]\d*\.\d*\.\d*\+commit\.[\d\w]*/g; let quotedVersionsRegexMatch = child.stdout.match(quotedVersionsRegex) if(quotedVersionsRegexMatch){ - let soljson2 = quotedVersionsRegexMatch.map((item) => item.replace('\'', 'v').replace('"', 'v')) - console.log('non nightly soljson versions found: ', soljson2); - if(soljson2) soljson = soljson.concat(soljson2); + let soljson2 = quotedVersionsRegexMatch.map((item) => item.replace('\'', 'v').replace('"', 'v')) + console.log('non nightly soljson versions found: ', soljson2); + if(soljson2) soljson = soljson.concat(soljson2); } const nightlyVersionsRegex = /\d*\.\d*\.\d-nightly.*\+commit\.[\d\w]*/g const nightlyVersionsRegexMatch = child.stdout.match(nightlyVersionsRegex) if(nightlyVersionsRegexMatch){ - let soljson3 = nightlyVersionsRegexMatch.map((item) => 'v' + item); - console.log('nightly soljson versions found: ', soljson3); - if(soljson3) soljson = soljson.concat(soljson3); + let soljson3 = nightlyVersionsRegexMatch.map((item) => 'v' + item); + console.log('nightly soljson versions found: ', soljson3); + if(soljson3) soljson = soljson.concat(soljson3); } if (soljson) { - // filter out duplicates - soljson = soljson.filter((item, index) => soljson.indexOf(item) === index); + // filter out duplicates + soljson = soljson.filter((item, index) => soljson.indexOf(item) === index); - // manually add some versions - soljson.push('v0.7.6+commit.7338295f'); + // manually add some versions + soljson.push('v0.7.6+commit.7338295f'); - console.log('soljson versions found: ', soljson, soljson.length); + console.log('soljson versions found: ', soljson, soljson.length); - for (let i = 0; i < soljson.length; i++) { - const version = soljson[i]; - if (version) { - let url = '' - - // if nightly - if (version.includes('nightly')) { - url = `https://binaries.soliditylang.org/bin/soljson-${version}.js`; - }else{ - url = `https://binaries.soliditylang.org/wasm/soljson-${version}.js`; - } - - const dir = './dist/apps/remix-ide/assets/js/soljson'; - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir); - } - - const path = `./dist/apps/remix-ide/assets/js/soljson/soljson-${version}.js`; - // check if the file exists - const exists = fs.existsSync(path); - if (!exists) { - console.log('URL:', url) - try { - // use curl to download the file - child_process.exec(`curl -o ${path} ${url}`, { encoding: 'utf8', cwd: process.cwd(), shell: true }) - } catch (e) { - console.log('Failed to download soljson' + version + ' from ' + url) - } - } + for (let i = 0; i < soljson.length; i++) { + const version = soljson[i]; + if (version) { + let url = '' + + // if nightly + if (version.includes('nightly')) { + url = `https://binaries.soliditylang.org/bin/soljson-${version}.js`; + }else{ + url = `https://binaries.soliditylang.org/wasm/soljson-${version}.js`; + } + + const dir = './dist/apps/remix-ide/assets/js/soljson'; + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir); + } + + const path = `./dist/apps/remix-ide/assets/js/soljson/soljson-${version}.js`; + // check if the file exists + const exists = fs.existsSync(path); + if (!exists) { + console.log('URL:', url) + try { + // use curl to download the file + child_process.exec(`curl -o ${path} ${url}`, { encoding: 'utf8', cwd: process.cwd(), shell: true }) + } catch (e) { + console.log('Failed to download soljson' + version + ' from ' + url) + } + } - } + } - } + } } diff --git a/apps/remix-ide/ci/lint-targets.js b/apps/remix-ide/ci/lint-targets.js index 7330cc9a3e..44e71d8c0f 100644 --- a/apps/remix-ide/ci/lint-targets.js +++ b/apps/remix-ide/ci/lint-targets.js @@ -5,15 +5,15 @@ const file = fs.readFileSync('projects.json') const projects = JSON.parse(file) console.log(Object.keys(projects.graph.nodes)) for(let node of Object.keys(projects.graph.nodes)){ - if(projects.graph.nodes[node].data.targets.lint){ + if(projects.graph.nodes[node].data.targets.lint){ console.log(projects.graph.nodes[node].data.name) const result = spawnSync('yarn', ['lint', projects.graph.nodes[node].data.name]) if(result.status == 0){ - console.log('success') + console.log('success') }else{ - console.log(result.stdout.toString()) - console.log(result.stderr.toString()) - exit(1) + console.log(result.stdout.toString()) + console.log(result.stderr.toString()) + exit(1) } - } + } } \ No newline at end of file diff --git a/apps/remix-ide/ci/splice_tests.js b/apps/remix-ide/ci/splice_tests.js index 3a51c3eb0c..57cc1db31b 100644 --- a/apps/remix-ide/ci/splice_tests.js +++ b/apps/remix-ide/ci/splice_tests.js @@ -7,21 +7,21 @@ let args = process.argv.slice(2) const jobsize = args[0] || 10; const job = args[1] || 0; exec(cmd, (error, stdout, stderr) => { - if (error) { - console.error(`error: ${error.message}`); - return; - } + if (error) { + console.error(`error: ${error.message}`); + return; + } - if (stderr) { - console.error(`stderr: ${stderr}`); - return; - } + if (stderr) { + console.error(`stderr: ${stderr}`); + return; + } - let files = stdout.split('\n').filter(f => f.includes('.test')).map(f => f.replace('dist/apps/remix-ide-e2e/src/tests/', '')).map(f => f.replace('.js', '')) - let splitIndex = Math.ceil(files.length / jobsize); - const parts = [] - for (let i = 0; i < jobsize; i++) { - parts.push(files.slice(i * splitIndex, (i + 1) * splitIndex)) - } - console.log(parts[job].join('\n')) - }); + let files = stdout.split('\n').filter(f => f.includes('.test')).map(f => f.replace('dist/apps/remix-ide-e2e/src/tests/', '')).map(f => f.replace('.js', '')) + let splitIndex = Math.ceil(files.length / jobsize); + const parts = [] + for (let i = 0; i < jobsize; i++) { + parts.push(files.slice(i * splitIndex, (i + 1) * splitIndex)) + } + console.log(parts[job].join('\n')) +}); diff --git a/apps/remix-ide/project.json b/apps/remix-ide/project.json index e0cc862959..395b9f4a6f 100644 --- a/apps/remix-ide/project.json +++ b/apps/remix-ide/project.json @@ -3,7 +3,7 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "apps/remix-ide/src", "projectType": "application", - "implicitDependencies": ["doc-gen", "doc-viewer", "etherscan", "vyper", "solhint", "walletconnect"], + "implicitDependencies": ["doc-gen", "doc-viewer", "etherscan", "vyper", "solhint", "walletconnect", "circuit-compiler"], "targets": { "build": { "executor": "@nrwl/webpack:webpack", diff --git a/apps/remix-ide/release-process.md b/apps/remix-ide/release-process.md index 511c8ad74e..1d9c89a7fa 100644 --- a/apps/remix-ide/release-process.md +++ b/apps/remix-ide/release-process.md @@ -45,9 +45,9 @@ This is not strictly speaking a release. Updating the remix site is done through - git reset --hard -master-commit-hash- - git push -f origin remix_live - CircleCI will build automaticaly and remix.ethereum.org will be updated + CircleCI will build automatically and remix.ethereum.org will be updated # remix-alpha.ethereum.org update -remix-alpha.ethereum.org is automaticaly updated every time commits are pushed to master +remix-alpha.ethereum.org is automatically updated every time commits are pushed to master diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 60d76fed6b..1fd677bdd8 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -1,26 +1,26 @@ 'use strict' -import { RunTab, makeUdapp } from './app/udapp' -import { RemixEngine } from './remixEngine' -import { RemixAppManager } from './remixAppManager' -import { ThemeModule } from './app/tabs/theme-module' -import { LocaleModule } from './app/tabs/locale-module' -import { NetworkModule } from './app/tabs/network-module' -import { Web3ProviderModule } from './app/tabs/web3-provider' -import { CompileAndRun } from './app/tabs/compile-and-run' -import { SidePanel } from './app/components/side-panel' -import { HiddenPanel } from './app/components/hidden-panel' -import { VerticalIcons } from './app/components/vertical-icons' -import { LandingPage } from './app/ui/landing-page/landing-page' -import { MainPanel } from './app/components/main-panel' -import { PermissionHandlerPlugin } from './app/plugins/permission-handler-plugin' -import { AstWalker } from '@remix-project/remix-astwalker' -import { LinkLibraries, DeployLibraries, OpenZeppelinProxy } from '@remix-project/core-plugin' -import { CodeParser } from './app/plugins/parser/code-parser' -import { SolidityScript } from './app/plugins/solidity-script' - -import { WalkthroughService } from './walkthroughService' - -import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports, GistHandler } from '@remix-project/core-plugin' +import {RunTab, makeUdapp} from './app/udapp' +import {RemixEngine} from './remixEngine' +import {RemixAppManager} from './remixAppManager' +import {ThemeModule} from './app/tabs/theme-module' +import {LocaleModule} from './app/tabs/locale-module' +import {NetworkModule} from './app/tabs/network-module' +import {Web3ProviderModule} from './app/tabs/web3-provider' +import {CompileAndRun} from './app/tabs/compile-and-run' +import {SidePanel} from './app/components/side-panel' +import {HiddenPanel} from './app/components/hidden-panel' +import {VerticalIcons} from './app/components/vertical-icons' +import {LandingPage} from './app/ui/landing-page/landing-page' +import {MainPanel} from './app/components/main-panel' +import {PermissionHandlerPlugin} from './app/plugins/permission-handler-plugin' +import {AstWalker} from '@remix-project/remix-astwalker' +import {LinkLibraries, DeployLibraries, OpenZeppelinProxy} from '@remix-project/core-plugin' +import {CodeParser} from './app/plugins/parser/code-parser' +import {SolidityScript} from './app/plugins/solidity-script' + +import {WalkthroughService} from './walkthroughService' + +import {OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports, GistHandler} from '@remix-project/core-plugin' import Registry from './app/state/registry' import { ConfigPlugin } from './app/plugins/config' @@ -53,6 +53,31 @@ import { electronTemplates } from './app/plugins/electron/templatesPlugin' import { xtermPlugin } from './app/plugins/electron/xtermPlugin' +import {ConfigPlugin} from './app/plugins/config' +import {StoragePlugin} from './app/plugins/storage' +import {Layout} from './app/panels/layout' +import {NotificationPlugin} from './app/plugins/notification' +import {Blockchain} from './blockchain/blockchain' +import {MergeVMProvider, LondonVMProvider, BerlinVMProvider, ShanghaiVMProvider} from './app/providers/vm-provider' +import {MainnetForkVMProvider} from './app/providers/mainnet-vm-fork-provider' +import {SepoliaForkVMProvider} from './app/providers/sepolia-vm-fork-provider' +import {GoerliForkVMProvider} from './app/providers/goerli-vm-fork-provider' +import {CustomForkVMProvider} from './app/providers/custom-vm-fork-provider' +import {HardhatProvider} from './app/providers/hardhat-provider' +import {GanacheProvider} from './app/providers/ganache-provider' +import {FoundryProvider} from './app/providers/foundry-provider' +import {ExternalHttpProvider} from './app/providers/external-http-provider' +import {InjectedProviderDefault} from './app/providers/injected-provider-default' +import {InjectedProviderTrustWallet} from './app/providers/injected-provider-trustwallet' +import {Injected0ptimismProvider} from './app/providers/injected-optimism-provider' +import {InjectedArbitrumOneProvider} from './app/providers/injected-arbitrum-one-provider' +import {InjectedEphemeryTestnetProvider} from './app/providers/injected-ephemery-testnet-provider' +import {InjectedSKALEChaosTestnetProvider} from './app/providers/injected-skale-chaos-testnet-provider' +import {FileDecorator} from './app/plugins/file-decorator' +import {CodeFormat} from './app/plugins/code-format' +import {SolidityUmlGen} from './app/plugins/solidity-umlgen' +import {ContractFlattener} from './app/plugins/contractFlattener' +import {OpenAIGpt} from './app/plugins/openaigpt' const isElectron = require('is-electron') @@ -61,6 +86,8 @@ const remixLib = require('@remix-project/remix-lib') import { QueryParams } from '@remix-project/remix-lib' import { SearchPlugin } from './app/tabs/search' import { ElectronProvider } from './app/files/electronProvider' +import {QueryParams} from '@remix-project/remix-lib' +import {SearchPlugin} from './app/tabs/search' const Storage = remixLib.Storage const RemixDProvider = require('./app/files/remixDProvider') @@ -76,12 +103,12 @@ const PluginManagerComponent = require('./app/components/plugin-manager-componen const CompileTab = require('./app/tabs/compile-tab') const SettingsTab = require('./app/tabs/settings-tab') const AnalysisTab = require('./app/tabs/analysis-tab') -const { DebuggerTab } = require('./app/tabs/debugger-tab') +const {DebuggerTab} = require('./app/tabs/debugger-tab') const TestTab = require('./app/tabs/test-tab') const FilePanel = require('./app/panels/file-panel') const Editor = require('./app/editor/editor') const Terminal = require('./app/panels/terminal') -const { TabProxy } = require('./app/panels/tab-proxy.js') +const {TabProxy} = require('./app/panels/tab-proxy.js') @@ -96,7 +123,7 @@ class AppComponent { // load app config const config = new Config(configStorage) - Registry.getInstance().put({ api: config, name: 'config' }) + Registry.getInstance().put({api: config, name: 'config'}) // load file system this._components.filesProviders = {} @@ -105,9 +132,7 @@ class AppComponent { api: this._components.filesProviders.browser, name: 'fileproviders/browser' }) - this._components.filesProviders.localhost = new RemixDProvider( - this.appManager - ) + this._components.filesProviders.localhost = new RemixDProvider(this.appManager) Registry.getInstance().put({ api: this._components.filesProviders.localhost, name: 'fileproviders/localhost' @@ -137,7 +162,7 @@ class AppComponent { this.panels = {} this.workspace = pluginLoader.get() this.engine = new RemixEngine() - this.engine.register(appManager); + this.engine.register(appManager) const matomoDomains = { 'remix-alpha.ethereum.org': 27, @@ -145,15 +170,8 @@ class AppComponent { 'remix.ethereum.org': 23, '6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod': 35 // remix desktop } - this.showMatamo = - matomoDomains[window.location.hostname] && - !Registry.getInstance() - .get('config') - .api.exists('settings/matomo-analytics') - this.walkthroughService = new WalkthroughService( - appManager, - this.showMatamo - ) + this.showMatamo = matomoDomains[window.location.hostname] && !Registry.getInstance().get('config').api.exists('settings/matomo-analytics') + this.walkthroughService = new WalkthroughService(appManager, this.showMatamo) const hosts = ['127.0.0.1:8080', '192.168.0.101:8080', 'localhost:8080'] // workaround for Electron support @@ -171,19 +189,20 @@ class AppComponent { this.themeModule = new ThemeModule() // ----------------- locale service --------------------------------- this.localeModule = new LocaleModule() - Registry.getInstance().put({ api: this.themeModule, name: 'themeModule' }) - Registry.getInstance().put({ api: this.localeModule, name: 'localeModule' }) + Registry.getInstance().put({api: this.themeModule, name: 'themeModule'}) + Registry.getInstance().put({api: this.localeModule, name: 'localeModule'}) // ----------------- editor service ---------------------------- const editor = new Editor() // wrapper around ace editor - Registry.getInstance().put({ api: editor, name: 'editor' }) - editor.event.register('requiringToSaveCurrentfile', () => + Registry.getInstance().put({api: editor, name: 'editor'}) + editor.event.register('requiringToSaveCurrentfile', (currentFile) => { fileManager.saveCurrentFile() - ) + if (currentFile.endsWith('.circom')) this.appManager.activatePlugin(['circuit-compiler']) + }) // ----------------- fileManager service ---------------------------- const fileManager = new FileManager(editor, appManager) - Registry.getInstance().put({ api: fileManager, name: 'filemanager' }) + Registry.getInstance().put({api: fileManager, name: 'filemanager'}) // ----------------- dGit provider --------------------------------- const dGitProvider = new DGitProvider() @@ -208,6 +227,9 @@ class AppComponent { // ----------------- ContractFlattener ---------------------------- const contractFlattener = new ContractFlattener() + // ----------------- Open AI -------------------------------------- + const openaigpt = new OpenAIGpt() + // ----------------- import content service ------------------------ const contentImport = new CompilerImports() @@ -241,9 +263,11 @@ class AppComponent { const foundryProvider = new FoundryProvider(blockchain) const externalHttpProvider = new ExternalHttpProvider(blockchain) const trustWalletInjectedProvider = new InjectedProviderTrustWallet() - const defaultInjectedProvider = new InjectedProviderDefault + const defaultInjectedProvider = new InjectedProviderDefault() const injected0ptimismProvider = new Injected0ptimismProvider() const injectedArbitrumOneProvider = new InjectedArbitrumOneProvider() + const injectedEphemeryTestnetProvider = new InjectedEphemeryTestnetProvider() + const injectedSKALEChaosTestnetProvider = new InjectedSKALEChaosTestnetProvider() // ----------------- convert offset to line/column service ----------- const offsetToLineColumnConverter = new OffsetToLineColumnConverter() Registry.getInstance().put({ @@ -253,11 +277,11 @@ class AppComponent { // ----------------- run script after each compilation results ----------- const compileAndRun = new CompileAndRun() // -------------------Terminal---------------------------------------- - makeUdapp(blockchain, compilersArtefacts, domEl => terminal.logHtml(domEl)) + makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl)) const terminal = new Terminal( - { appManager, blockchain }, + {appManager, blockchain}, { - getPosition: event => { + getPosition: (event) => { const limitUp = 36 const limitDown = 20 const height = window.innerHeight @@ -320,12 +344,15 @@ class AppComponent { trustWalletInjectedProvider, injected0ptimismProvider, injectedArbitrumOneProvider, + injectedEphemeryTestnetProvider, + injectedSKALEChaosTestnetProvider, this.walkthroughService, search, solidityumlgen, contractFlattener, solidityScript, - templates + templates, + openaigpt ]) //---- fs plugin @@ -344,7 +371,7 @@ class AppComponent { // LAYOUT & SYSTEM VIEWS const appPanel = new MainPanel() - Registry.getInstance().put({ api: this.mainview, name: 'mainview' }) + Registry.getInstance().put({api: this.mainview, name: 'mainview'}) const tabProxy = new TabProxy(fileManager, editor) this.engine.register([appPanel, tabProxy]) @@ -353,42 +380,18 @@ class AppComponent { this.sidePanel = new SidePanel() this.hiddenPanel = new HiddenPanel() - const pluginManagerComponent = new PluginManagerComponent( - appManager, - this.engine - ) + const pluginManagerComponent = new PluginManagerComponent(appManager, this.engine) const filePanel = new FilePanel(appManager) - const landingPage = new LandingPage( - appManager, - this.menuicons, - fileManager, - filePanel, - contentImport - ) - this.settings = new SettingsTab( - Registry.getInstance().get('config').api, - editor, - appManager - ) + const landingPage = new LandingPage(appManager, this.menuicons, fileManager, filePanel, contentImport) + this.settings = new SettingsTab(Registry.getInstance().get('config').api, editor, appManager) - this.engine.register([ - this.menuicons, - landingPage, - this.hiddenPanel, - this.sidePanel, - filePanel, - pluginManagerComponent, - this.settings - ]) + this.engine.register([this.menuicons, landingPage, this.hiddenPanel, this.sidePanel, filePanel, pluginManagerComponent, this.settings]) // CONTENT VIEWS & DEFAULT PLUGINS const openZeppelinProxy = new OpenZeppelinProxy(blockchain) const linkLibraries = new LinkLibraries(blockchain) const deployLibraries = new DeployLibraries(blockchain) - const compileTab = new CompileTab( - Registry.getInstance().get('config').api, - Registry.getInstance().get('filemanager').api - ) + const compileTab = new CompileTab(Registry.getInstance().get('config').api, Registry.getInstance().get('filemanager').api) const run = new RunTab( blockchain, Registry.getInstance().get('config').api, @@ -428,10 +431,10 @@ class AppComponent { ]) this.layout.panels = { - tabs: { plugin: tabProxy, active: true }, - editor: { plugin: editor, active: true }, - main: { plugin: appPanel, active: false }, - terminal: { plugin: terminal, active: true, minimized: false } + tabs: {plugin: tabProxy, active: true}, + editor: {plugin: editor, active: true}, + main: {plugin: appPanel, active: false}, + terminal: {plugin: terminal, active: true, minimized: false} } } @@ -447,12 +450,33 @@ class AppComponent { await this.appManager.activatePlugin(['layout']) await this.appManager.activatePlugin(['notification']) await this.appManager.activatePlugin(['editor']) - await this.appManager.activatePlugin(['permissionhandler', 'theme', 'locale', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter']) + await this.appManager.activatePlugin([ + 'permissionhandler', + 'theme', + 'locale', + 'fileManager', + 'compilerMetadata', + 'compilerArtefacts', + 'network', + 'web3Provider', + 'offsetToLineColumnConverter' + ]) await this.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs']) await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately await this.appManager.activatePlugin(['home']) await this.appManager.activatePlugin(['settings', 'config']) - await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'codeParser', 'codeFormatter', 'fileDecorator', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler']) + await this.appManager.activatePlugin([ + 'hiddenPanel', + 'pluginManager', + 'codeParser', + 'codeFormatter', + 'fileDecorator', + 'terminal', + 'blockchain', + 'fetchAndCompile', + 'contentImport', + 'gistHandler' + ]) await this.appManager.activatePlugin(['settings']) await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder']) await this.appManager.activatePlugin(['solidity-script', 'remix-templates']) @@ -472,6 +496,7 @@ class AppComponent { await this.appManager.registerContextMenuItems() } ) + await this.appManager.activatePlugin(['solidity-script', 'openaigpt']) await this.appManager.activatePlugin(['filePanel']) @@ -483,9 +508,7 @@ class AppComponent { .then(async () => { try { if (params.deactivate) { - await this.appManager.deactivatePlugin( - params.deactivate.split(',') - ) + await this.appManager.deactivatePlugin(params.deactivate.split(',')) } } catch (e) { console.log(e) @@ -495,10 +518,7 @@ class AppComponent { this.menuicons.select('solidity') } else { // If plugins are loaded from the URL params, we focus on the last one. - if ( - this.appManager.pluginLoader.current === 'queryParams' && - this.workspace.length > 0 - ) { + if (this.appManager.pluginLoader.current === 'queryParams' && this.workspace.length > 0) { this.menuicons.select(this.workspace[this.workspace.length - 1]) } else { this.appManager.call('tabs', 'focus', 'home') @@ -515,17 +535,13 @@ class AppComponent { } if (params.calls) { - const calls = params.calls.split("///"); + const calls = params.calls.split('///') // call all functions in the list, one after the other for (const call of calls) { - const callDetails = call.split("//"); + const callDetails = call.split('//') if (callDetails.length > 1) { - this.appManager.call( - "notification", - "toast", - `initiating ${callDetails[0]} and calling "${callDetails[1]}" ...` - ); + this.appManager.call('notification', 'toast', `initiating ${callDetails[0]} and calling "${callDetails[1]}" ...`) // @todo(remove the timeout when activatePlugin is on 0.3.0) try { diff --git a/apps/remix-ide/src/app/components/hidden-panel.tsx b/apps/remix-ide/src/app/components/hidden-panel.tsx index 6aa78a4052..88b095b625 100644 --- a/apps/remix-ide/src/app/components/hidden-panel.tsx +++ b/apps/remix-ide/src/app/components/hidden-panel.tsx @@ -1,9 +1,9 @@ // eslint-disable-next-line no-use-before-define import React from 'react' -import { AbstractPanel } from './panel' +import {AbstractPanel} from './panel' import * as packageJson from '../../../../../package.json' -import { RemixPluginPanel } from '@remix-ui/panel' -import { PluginViewWrapper } from '@remix-ui/helper' +import {RemixPluginPanel} from '@remix-ui/panel' +import {PluginViewWrapper} from '@remix-ui/helper' const profile = { name: 'hiddenPanel', @@ -16,35 +16,37 @@ const profile = { export class HiddenPanel extends AbstractPanel { el: HTMLElement dispatch: React.Dispatch = () => {} - constructor () { + constructor() { super(profile) this.el = document.createElement('div') this.el.setAttribute('class', 'pluginsContainer') } - addView (profile: any, view: any): void { + addView(profile: any, view: any): void { super.removeView(profile) super.addView(profile, view) this.renderComponent() } - updateComponent (state: any) { - return } plugins={state.plugins}/> + updateComponent(state: any) { + return } plugins={state.plugins} /> } - setDispatch (dispatch: React.Dispatch) { + setDispatch(dispatch: React.Dispatch) { this.dispatch = dispatch } - render() { + render() { return ( -
- ); +
+ +
+ ) } - renderComponent () { + renderComponent() { this.dispatch({ - plugins: this.plugins, + plugins: this.plugins }) } } diff --git a/apps/remix-ide/src/app/components/main-panel.tsx b/apps/remix-ide/src/app/components/main-panel.tsx index d6dee613fd..15311a6173 100644 --- a/apps/remix-ide/src/app/components/main-panel.tsx +++ b/apps/remix-ide/src/app/components/main-panel.tsx @@ -1,8 +1,8 @@ import React from 'react' // eslint-disable-line -import { AbstractPanel } from './panel' -import { RemixPluginPanel } from '@remix-ui/panel' +import {AbstractPanel} from './panel' +import {RemixPluginPanel} from '@remix-ui/panel' import packageJson from '../../../../../package.json' -import { PluginViewWrapper } from '@remix-ui/helper' +import {PluginViewWrapper} from '@remix-ui/helper' const profile = { name: 'mainPanel', @@ -13,56 +13,60 @@ const profile = { } export class MainPanel extends AbstractPanel { - element: HTMLDivElement - dispatch: React.Dispatch = () => {} - constructor (config) { - super(profile) - this.element = document.createElement('div') - this.element.setAttribute('data-id', 'mainPanelPluginsContainer') - this.element.setAttribute('style', 'height: 100%; width: 100%;') - // this.config = config - } + element: HTMLDivElement + dispatch: React.Dispatch = () => {} + constructor(config) { + super(profile) + this.element = document.createElement('div') + this.element.setAttribute('data-id', 'mainPanelPluginsContainer') + this.element.setAttribute('style', 'height: 100%; width: 100%;') + // this.config = config + } - setDispatch (dispatch: React.Dispatch) { - this.dispatch = dispatch - } + setDispatch(dispatch: React.Dispatch) { + this.dispatch = dispatch + } - onActivation () { - this.renderComponent() - } + onActivation() { + this.renderComponent() + } - focus (name) { - this.emit('focusChanged', name) - super.focus(name) - this.renderComponent() - } + focus(name) { + this.emit('focusChanged', name) + super.focus(name) + this.renderComponent() + } - addView (profile, view) { - super.addView(profile, view) - this.renderComponent() - } + addView(profile, view) { + super.addView(profile, view) + this.renderComponent() + } - removeView (profile) { - super.removeView(profile) - this.renderComponent() - } + removeView(profile) { + super.removeView(profile) + this.renderComponent() + } - async showContent (name) { - super.showContent(name) - this.renderComponent() - } + async showContent(name) { + super.showContent(name) + this.renderComponent() + } - renderComponent () { - this.dispatch({ - plugins: this.plugins - }) - } + renderComponent() { + this.dispatch({ + plugins: this.plugins + }) + } - render() { - return
- } + render() { + return ( +
+ +
+ ) + } - updateComponent (state: any) { - return } plugins={state.plugins}/> - } + updateComponent(state: any) { + return } plugins={state.plugins} /> + } } diff --git a/apps/remix-ide/src/app/components/preload.tsx b/apps/remix-ide/src/app/components/preload.tsx index f607264d63..ec9be4597a 100644 --- a/apps/remix-ide/src/app/components/preload.tsx +++ b/apps/remix-ide/src/app/components/preload.tsx @@ -1,144 +1,174 @@ -import { RemixApp } from '@remix-ui/app' -import React, { useEffect, useRef, useState } from 'react' -import { render } from 'react-dom' +import {RemixApp} from '@remix-ui/app' +import React, {useEffect, useRef, useState} from 'react' +import {render} from 'react-dom' import * as packageJson from '../../../../../package.json' -import { fileSystem, fileSystems } from '../files/fileSystem' -import { indexedDBFileSystem } from '../files/filesystems/indexedDB' -import { localStorageFS } from '../files/filesystems/localStorage' -import { fileSystemUtility, migrationTestData } from '../files/filesystems/fileSystemUtility' +import {fileSystem, fileSystems} from '../files/fileSystem' +import {indexedDBFileSystem} from '../files/filesystems/indexedDB' +import {localStorageFS} from '../files/filesystems/localStorage' +import {fileSystemUtility, migrationTestData} from '../files/filesystems/fileSystemUtility' import './styles/preload.css' -const _paq = window._paq = window._paq || [] +const _paq = (window._paq = window._paq || []) export const Preload = () => { + const [supported, setSupported] = useState(true) + const [error, setError] = useState(false) + const [showDownloader, setShowDownloader] = useState(false) + const remixFileSystems = useRef(new fileSystems()) + const remixIndexedDB = useRef(new indexedDBFileSystem()) + const localStorageFileSystem = useRef(new localStorageFS()) + // url parameters to e2e test the fallbacks and error warnings + const testmigrationFallback = useRef( + window.location.hash.includes('e2e_testmigration_fallback=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:' + ) + const testmigrationResult = useRef( + window.location.hash.includes('e2e_testmigration=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:' + ) + const testBlockStorage = useRef( + window.location.hash.includes('e2e_testblock_storage=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:' + ) - const [supported, setSupported] = useState(true) - const [error, setError] = useState(false) - const [showDownloader, setShowDownloader] = useState(false) - const remixFileSystems = useRef(new fileSystems()) - const remixIndexedDB = useRef(new indexedDBFileSystem()) - const localStorageFileSystem = useRef(new localStorageFS()) - // url parameters to e2e test the fallbacks and error warnings - const testmigrationFallback = useRef(window.location.hash.includes('e2e_testmigration_fallback=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:') - const testmigrationResult = useRef(window.location.hash.includes('e2e_testmigration=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:') - const testBlockStorage = useRef(window.location.hash.includes('e2e_testblock_storage=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:') - - function loadAppComponent() { - import('../../app').then((AppComponent) => { - const appComponent = new AppComponent.default() - appComponent.run().then(() => { - render( - <> - - , - document.getElementById('root') - ) - }) - }).catch(err => { - _paq.push(['trackEvent', 'Preload', 'error', err && err.message]) - console.error('Error loading Remix:', err) - setError(true) + function loadAppComponent() { + import('../../app') + .then((AppComponent) => { + const appComponent = new AppComponent.default() + appComponent.run().then(() => { + render( + <> + + , + document.getElementById('root') + ) }) - } + }) + .catch((err) => { + _paq.push(['trackEvent', 'Preload', 'error', err && err.message]) + console.error('Error loading Remix:', err) + setError(true) + }) + } - const downloadBackup = async () => { - setShowDownloader(false) - const fsUtility = new fileSystemUtility() - await fsUtility.downloadBackup(remixFileSystems.current.fileSystems['localstorage']) - await migrateAndLoad() - } + const downloadBackup = async () => { + setShowDownloader(false) + const fsUtility = new fileSystemUtility() + await fsUtility.downloadBackup(remixFileSystems.current.fileSystems['localstorage']) + await migrateAndLoad() + } - const migrateAndLoad = async () => { - setShowDownloader(false) - const fsUtility = new fileSystemUtility() - const migrationResult = await fsUtility.migrate(localStorageFileSystem.current, remixIndexedDB.current) - _paq.push(['trackEvent', 'Migrate', 'result', migrationResult?'success' : 'fail']) - await setFileSystems() - } + const migrateAndLoad = async () => { + setShowDownloader(false) + const fsUtility = new fileSystemUtility() + const migrationResult = await fsUtility.migrate(localStorageFileSystem.current, remixIndexedDB.current) + _paq.push(['trackEvent', 'Migrate', 'result', migrationResult ? 'success' : 'fail']) + await setFileSystems() + } - const setFileSystems = async() => { - const fsLoaded = await remixFileSystems.current.setFileSystem([(testmigrationFallback.current || testBlockStorage.current)? null: remixIndexedDB.current, testBlockStorage.current? null:localStorageFileSystem.current]) - if (fsLoaded) { - console.log(fsLoaded.name + ' activated') - _paq.push(['trackEvent', 'Storage', 'activate', fsLoaded.name]) - loadAppComponent() - } else { - _paq.push(['trackEvent', 'Storage', 'error', 'no supported storage']) - setSupported(false) - } + const setFileSystems = async () => { + const fsLoaded = await remixFileSystems.current.setFileSystem([ + testmigrationFallback.current || testBlockStorage.current ? null : remixIndexedDB.current, + testBlockStorage.current ? null : localStorageFileSystem.current + ]) + if (fsLoaded) { + console.log(fsLoaded.name + ' activated') + _paq.push(['trackEvent', 'Storage', 'activate', fsLoaded.name]) + loadAppComponent() + } else { + _paq.push(['trackEvent', 'Storage', 'error', 'no supported storage']) + setSupported(false) } + } - const testmigration = async() => { - if (testmigrationResult.current) { - const fsUtility = new fileSystemUtility() - fsUtility.populateWorkspace(migrationTestData, remixFileSystems.current.fileSystems['localstorage'].fs) - } + const testmigration = async () => { + if (testmigrationResult.current) { + const fsUtility = new fileSystemUtility() + fsUtility.populateWorkspace(migrationTestData, remixFileSystems.current.fileSystems['localstorage'].fs) } + } - useEffect(() => { - async function loadStorage() { - await remixFileSystems.current.addFileSystem(remixIndexedDB.current) || _paq.push(['trackEvent', 'Storage', 'error', 'indexedDB not supported']) - await remixFileSystems.current.addFileSystem(localStorageFileSystem.current) || _paq.push(['trackEvent', 'Storage', 'error', 'localstorage not supported']) - await testmigration() - remixIndexedDB.current.loaded && await remixIndexedDB.current.checkWorkspaces() - localStorageFileSystem.current.loaded && await localStorageFileSystem.current.checkWorkspaces() - remixIndexedDB.current.loaded && ( (remixIndexedDB.current.hasWorkSpaces || !localStorageFileSystem.current.hasWorkSpaces)? await setFileSystems():setShowDownloader(true)) - !remixIndexedDB.current.loaded && await setFileSystems() - } - loadStorage() - }, []) + useEffect(() => { + async function loadStorage() { + ;(await remixFileSystems.current.addFileSystem(remixIndexedDB.current)) || _paq.push(['trackEvent', 'Storage', 'error', 'indexedDB not supported']) + ;(await remixFileSystems.current.addFileSystem(localStorageFileSystem.current)) || _paq.push(['trackEvent', 'Storage', 'error', 'localstorage not supported']) + await testmigration() + remixIndexedDB.current.loaded && (await remixIndexedDB.current.checkWorkspaces()) + localStorageFileSystem.current.loaded && (await localStorageFileSystem.current.checkWorkspaces()) + remixIndexedDB.current.loaded && (remixIndexedDB.current.hasWorkSpaces || !localStorageFileSystem.current.hasWorkSpaces ? await setFileSystems() : setShowDownloader(true)) + !remixIndexedDB.current.loaded && (await setFileSystems()) + } + loadStorage() + }, []) - return <> -
-
- {logo} -
- REMIX IDE -
- v{packageJson.version} -
-
- {!supported ? -
- Your browser does not support any of the filesystems required by Remix. - Either change the settings in your browser or use a supported browser. -
: null} - {error ? -
- An unknown error has occurred while loading the application.

- Doing a hard refresh might fix this issue:

-
- Windows:

- - Chrome: CTRL + F5 or CTRL + Reload Button

- - Firefox: CTRL + SHIFT + R or CTRL + F5

-
-
- MacOS:

- - Chrome & FireFox: CMD + SHIFT + R or SHIFT + Reload Button

-
-
- Linux:

- - Chrome & FireFox: CTRL + SHIFT + R

-
-
: null} - {showDownloader ? -
- This app will be updated now. Please download a backup of your files now to make sure you don't lose your work. -

- You don't need to do anything else, your files will be available when the app loads. -
{ await downloadBackup() }} data-id='downloadbackup-btn' className='btn btn-primary mt-1'>download backup
-
{ await migrateAndLoad() }} data-id='skipbackup-btn' className='btn btn-primary mt-1'>skip backup
-
: null} - {(supported && !error && !showDownloader) ? -
- -
: null} + return ( + <> +
+
+ {logo} +
+ REMIX IDE +
+ v{packageJson.version} +
+ {!supported ? ( +
+ Your browser does not support any of the filesystems required by Remix. Either change the settings in your browser or use a supported browser. +
+ ) : null} + {error ? ( +
+ An unknown error has occurred while loading the application. +

+ Doing a hard refresh might fix this issue:

+
+ Windows:

- Chrome: CTRL + F5 or CTRL + Reload Button +

- Firefox: CTRL + SHIFT + R or CTRL + F5

+
+
+ MacOS:

- Chrome & FireFox: CMD + SHIFT + R or SHIFT + Reload Button

+
+
+ Linux:

- Chrome & FireFox: CTRL + SHIFT + R

+
+
+ ) : null} + {showDownloader ? ( +
+ This app will be updated now. Please download a backup of your files now to make sure you don't lose your work. +

+ You don't need to do anything else, your files will be available when the app loads. +
{ + await downloadBackup() + }} + data-id="downloadbackup-btn" + className="btn btn-primary mt-1" + > + download backup +
+
{ + await migrateAndLoad() + }} + data-id="skipbackup-btn" + className="btn btn-primary mt-1" + > + skip backup +
+
+ ) : null} + {supported && !error && !showDownloader ? ( +
+ +
+ ) : null} +
+ ) } - -const logo = +const logo = ( + - + +) diff --git a/apps/remix-ide/src/app/components/side-panel.tsx b/apps/remix-ide/src/app/components/side-panel.tsx index 8b58171492..6ea715f420 100644 --- a/apps/remix-ide/src/app/components/side-panel.tsx +++ b/apps/remix-ide/src/app/components/side-panel.tsx @@ -1,10 +1,10 @@ // eslint-disable-next-line no-use-before-define import React from 'react' -import { AbstractPanel } from './panel' -import { RemixPluginPanel } from '@remix-ui/panel' +import {AbstractPanel} from './panel' +import {RemixPluginPanel} from '@remix-ui/panel' import packageJson from '../../../../../package.json' -import { RemixUIPanelHeader } from '@remix-ui/panel' -import { PluginViewWrapper } from '@remix-ui/helper' +import {RemixUIPanelHeader} from '@remix-ui/panel' +import {PluginViewWrapper} from '@remix-ui/helper' // const csjs = require('csjs-inject') const sidePanel = { @@ -79,14 +79,17 @@ export class SidePanel extends AbstractPanel { this.renderComponent() } - setDispatch (dispatch: React.Dispatch) { + setDispatch(dispatch: React.Dispatch) { this.dispatch = dispatch } - render() { + render() { return ( -
- ); +
+ {' '} + +
+ ) } updateComponent(state: any) { diff --git a/apps/remix-ide/src/app/components/vertical-icons.tsx b/apps/remix-ide/src/app/components/vertical-icons.tsx index 24d5b93b2b..f43a5505c3 100644 --- a/apps/remix-ide/src/app/components/vertical-icons.tsx +++ b/apps/remix-ide/src/app/components/vertical-icons.tsx @@ -1,11 +1,11 @@ // eslint-disable-next-line no-use-before-define import React from 'react' import packageJson from '../../../../../package.json' -import { Plugin } from '@remixproject/engine' -import { EventEmitter } from 'events' -import { IconRecord, RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel' -import { Profile } from '@remixproject/plugin-utils' -import { PluginViewWrapper } from '@remix-ui/helper' +import {Plugin} from '@remixproject/engine' +import {EventEmitter} from 'events' +import {IconRecord, RemixUiVerticalIconsPanel} from '@remix-ui/vertical-icons-panel' +import {Profile} from '@remixproject/plugin-utils' +import {PluginViewWrapper} from '@remix-ui/helper' const profile = { name: 'menuicons', @@ -21,44 +21,51 @@ export class VerticalIcons extends Plugin { htmlElement: HTMLDivElement icons: Record = {} dispatch: React.Dispatch = () => {} - constructor () { + constructor() { super(profile) this.events = new EventEmitter() this.htmlElement = document.createElement('div') this.htmlElement.setAttribute('id', 'icon-panel') } - renderComponent () { - const fixedOrder = ['filePanel', 'search', 'solidity','udapp', 'debugger', 'solidityStaticAnalysis', 'solidityUnitTesting', 'pluginManager'] + renderComponent() { + const fixedOrder = ['filePanel', 'search', 'solidity', 'udapp', 'debugger', 'solidityStaticAnalysis', 'solidityUnitTesting', 'pluginManager'] - const divived = Object.values(this.icons).map((value) => { return { - ...value, - isRequired: fixedOrder.indexOf(value.profile.name) > -1 - }}).sort((a,b) => { - return a.timestamp - b.timestamp - }) + const divived = Object.values(this.icons) + .map((value) => { + return { + ...value, + isRequired: fixedOrder.indexOf(value.profile.name) > -1 + } + }) + .sort((a, b) => { + return a.timestamp - b.timestamp + }) - const required = divived.filter((value) => value.isRequired).sort((a,b) => { - return fixedOrder.indexOf(a.profile.name) - fixedOrder.indexOf(b.profile.name) - }) + const required = divived + .filter((value) => value.isRequired) + .sort((a, b) => { + return fixedOrder.indexOf(a.profile.name) - fixedOrder.indexOf(b.profile.name) + }) const sorted: IconRecord[] = [ ...required, - ...divived.filter((value) => { return !value.isRequired }) + ...divived.filter((value) => { + return !value.isRequired + }) ] this.dispatch({ verticalIconsPlugin: this, icons: sorted }) - } - setDispatch (dispatch: React.Dispatch) { + setDispatch(dispatch: React.Dispatch) { this.dispatch = dispatch } - onActivation () { + onActivation() { this.renderComponent() this.on('sidePanel', 'focusChanged', (name: string) => { Object.keys(this.icons).map((o) => { @@ -69,7 +76,7 @@ export class VerticalIcons extends Plugin { }) } - async linkContent (profile: Profile) { + async linkContent(profile: Profile) { if (!profile.icon) return if (!profile.kind) profile.kind = 'none' this.icons[profile.name] = { @@ -81,7 +88,7 @@ export class VerticalIcons extends Plugin { this.renderComponent() } - unlinkContent (profile: Profile) { + unlinkContent(profile: Profile) { delete this.icons[profile.name] this.renderComponent() } @@ -95,7 +102,7 @@ export class VerticalIcons extends Plugin { * Set an icon as active * @param {string} name Name of profile of the module to activate */ - select (name: string) { + select(name: string) { // TODO: Only keep `this.emit` (issue#2210) this.emit('showContent', name) this.events.emit('showContent', name) @@ -105,22 +112,21 @@ export class VerticalIcons extends Plugin { * Toggles the side panel for plugin * @param {string} name Name of profile of the module to activate */ - toggle (name: string) { + toggle(name: string) { // TODO: Only keep `this.emit` (issue#2210) this.emit('toggleContent', name) this.events.emit('toggleContent', name) } - updateComponent(state: any){ - return + updateComponent(state: any) { + return } - render() { + render() { return ( -
- ); +
+ +
+ ) } } diff --git a/apps/remix-ide/src/app/editor/editor.js b/apps/remix-ide/src/app/editor/editor.js index 9a0d58e2e5..46bd19e146 100644 --- a/apps/remix-ide/src/app/editor/editor.js +++ b/apps/remix-ide/src/app/editor/editor.js @@ -13,7 +13,7 @@ const profile = { name: 'editor', description: 'service - editor', version: packageJson.version, - methods: ['highlight', 'discardHighlight', 'clearAnnotations', 'addLineText', 'discardLineTexts', 'addAnnotation', 'gotoLine', 'revealRange', 'getCursorPosition', 'open', 'addModel','addErrorMarker', 'clearErrorMarkers', 'getText'], + methods: ['highlight', 'discardHighlight', 'clearAnnotations', 'addLineText', 'discardLineTexts', 'addAnnotation', 'gotoLine', 'revealRange', 'getCursorPosition', 'open', 'addModel','addErrorMarker', 'clearErrorMarkers', 'getText', 'getPositionAt'], } class Editor extends Plugin { @@ -51,7 +51,8 @@ class Editor extends Plugin { rs: 'rust', cairo: 'cairo', ts: 'typescript', - move: 'move' + move: 'move', + circom: 'circom' } this.activated = false @@ -99,8 +100,8 @@ class Editor extends Plugin { this.ref.clearDecorationsByPlugin = (filePath, plugin, typeOfDecoration) => this.clearDecorationsByPlugin(filePath, plugin, typeOfDecoration) this.ref.keepDecorationsFor = (name, typeOfDecoration) => this.keepDecorationsFor(name, typeOfDecoration) }} id='editorView'> - -
+ +
} renderComponent () { @@ -174,8 +175,8 @@ class Editor extends Plugin { } this.saveTimeout = window.setTimeout(() => { - this.triggerEvent('contentChanged', []) - this.triggerEvent('requiringToSaveCurrentfile', []) + this.triggerEvent('contentChanged', [currentFile, input]) + this.triggerEvent('requiringToSaveCurrentfile', [currentFile]) }, 500) } @@ -293,7 +294,7 @@ class Editor extends Plugin { * Get the text in the current session, if any. * @param {string} url Address of the content to retrieve. */ - getText (url) { + getText (url) { if (this.sessions[url]) { return this.sessions[url].getValue() } @@ -578,6 +579,10 @@ class Editor extends Plugin { this.clearDecorationsByPlugin(session, from, 'lineTextPerFile', this.registeredDecorations, this.currentDecorations) } } + + getPositionAt(offset) { + return this.api.getPositionAt(offset) + } } module.exports = Editor diff --git a/apps/remix-ide/src/app/files/fileManager.ts b/apps/remix-ide/src/app/files/fileManager.ts index e8df1f79d8..ceb39ef969 100644 --- a/apps/remix-ide/src/app/files/fileManager.ts +++ b/apps/remix-ide/src/app/files/fileManager.ts @@ -1,3 +1,4 @@ + 'use strict' import { saveAs } from 'file-saver' import JSZip from 'jszip' @@ -23,8 +24,8 @@ const profile = { icon: 'assets/img/fileManager.webp', permission: true, version: packageJson.version, - methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', - 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'selectFolder', 'setFile', 'switchFile', 'refresh', + methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'writeMultipleFiles', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', + 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'saveCurrentFile', 'setBatchFiles', 'isGitRepo'], kind: 'file-system' } @@ -223,6 +224,38 @@ class FileManager extends Plugin { } } + /** + * Set the content of multiple files + * @param {string[]} filePaths paths of the files + * @param {string[]} data content to write to each file + * @param {string} folderPath base folder path + * @returns {void} + */ + async writeMultipleFiles(filePaths: string[], fileData: string[], folderPath: string) { + if (this.currentRequest) { + const canCall = await this.askUserPermission(`writeFile`, `will write multiple files to ${folderPath}...`) + const required = this.appManager.isRequired(this.currentRequest.from) + if (canCall && !required) { + this.call('notification', 'toast', fileChangedToastMsg(this.currentRequest.from, folderPath)) + } + } + try { + for (let i = 0; i < filePaths.length; i++) { + const installPath = folderPath + "/" + filePaths[i] + + let path = this.normalize(installPath) + path = this.limitPluginScope(path) + + if (!await this.exists(path)) { + await this._setFileInternal(path, fileData[i]) + this.emit('fileAdded', path) + } + } + } catch (e) { + throw new Error(e) + } + } + /** * Return the content of a specific file * @param {string} path path of the file @@ -353,7 +386,7 @@ class FileManager extends Plugin { async zipDir(dirPath, zip) { const filesAndFolders = await this.readdir(dirPath) - for(let path in filesAndFolders) { + for (let path in filesAndFolders) { if (filesAndFolders[path].isDirectory) await this.zipDir(path, zip) else { path = this.normalize(path) @@ -367,15 +400,15 @@ class FileManager extends Plugin { try { const downloadFileName = helper.extractNameFromKey(path) if (await this.isDirectory(path)) { - const zip = new JSZip() - await this.zipDir(path, zip) - const content = await zip.generateAsync({type: 'blob'}) - saveAs(content, `${downloadFileName}.zip`) - } else { - path = this.normalize(path) - const content: any = await this.readFile(path) - saveAs(new Blob([content]), downloadFileName) - } + const zip = new JSZip() + await this.zipDir(path, zip) + const content = await zip.generateAsync({ type: 'blob' }) + saveAs(content, `${downloadFileName}.zip`) + } else { + path = this.normalize(path) + const content: any = await this.readFile(path) + saveAs(new Blob([content]), downloadFileName) + } } catch (e) { throw new Error(e) } @@ -589,7 +622,7 @@ class FileManager extends Plugin { // TODO : Add permission // TODO : Change Provider to Promise return new Promise((resolve, reject) => { - provider.set(path, content, (error) => { + provider.set(path, content, async (error) => { if (error) reject(error) this.syncEditor(path) this.emit('fileSaved', path) @@ -666,7 +699,7 @@ class FileManager extends Plugin { file = resolved.file await this.saveCurrentFile() if (this.currentFile() === file) return - + const provider = resolved.provider this._deps.config.set('currentFile', file) this.openedFiles[file] = file @@ -674,7 +707,7 @@ class FileManager extends Plugin { let content = '' try { content = await provider.get(file) - + } catch (error) { console.log(error) throw error @@ -694,7 +727,7 @@ class FileManager extends Plugin { // TODO: Only keep `this.emit` (issue#2210) this.emit('currentFileChanged', file) this.events.emit('currentFileChanged', file) - return true + return true } } @@ -759,14 +792,14 @@ class FileManager extends Plugin { return collectList(path) } - async fileList (dirPath) { + async fileList(dirPath) { const paths: any = await this.readdir(dirPath) - for( const path in paths) - if(paths[path].isDirectory) delete paths[path] + for (const path in paths) + if (paths[path].isDirectory) delete paths[path] return Object.keys(paths) } - isRemixDActive () { + isRemixDActive() { return this.appManager.isActive('remixd') } @@ -781,7 +814,7 @@ class FileManager extends Plugin { provider.get(currentFile, (error, oldContent) => { provider.set(currentFile, input, (error) => { if (error) { - if (error.message ) this.call('notification', 'toast', + if (error.message) this.call('notification', 'toast', error.message.indexOf( 'LocalStorage is full') !== -1 ? storageFullMessage() : error.message @@ -789,7 +822,7 @@ class FileManager extends Plugin { provider.set(currentFile, oldContent) return console.error(error) } else { - this.emit('fileSaved', currentFile) + this.emit('fileSaved', currentFile) } }) }) @@ -805,10 +838,10 @@ class FileManager extends Plugin { if (path !== currentFile) return const provider = this.fileProviderOf(currentFile) if (provider) { - try{ + try { const content = await provider.get(currentFile) - if(content) this.editor.setText(currentFile, content) - }catch(error){ + if (content) this.editor.setText(currentFile, content) + } catch (error) { console.log(error) } } else { @@ -829,7 +862,7 @@ class FileManager extends Plugin { } await self.syncEditor(fileProvider + file) } else { - try{ + try { const name = await helper.createNonClashingNameAsync(file, self._deps.filesProviders[fileProvider]) if (helper.checkSpecialChars(name)) { this.call('notification', 'alert', { @@ -844,7 +877,7 @@ class FileManager extends Plugin { } self.syncEditor(fileProvider + name) } - }catch(error){ + } catch (error) { if (error) { this.call('notification', 'alert', { id: 'fileManagerAlert', @@ -870,21 +903,72 @@ class FileManager extends Plugin { } } - async isGitRepo (): Promise { + async isGitRepo(): Promise { const path = '.git' const exists = await this.exists(path) return exists } + + async moveFileIsAllowed (src: string, dest: string) { + try { + src = this.normalize(src) + dest = this.normalize(dest) + src = this.limitPluginScope(src) + dest = this.limitPluginScope(dest) + await this._handleExists(src, `Cannot move ${src}. Path does not exist.`) + await this._handleExists(dest, `Cannot move content into ${dest}. Path does not exist.`) + await this._handleIsFile(src, `Cannot move ${src}. Path is not a file.`) + await this._handleIsDir(dest, `Cannot move content into ${dest}. Path is not directory.`) + const fileName = helper.extractNameFromKey(src) + + if (await this.exists(dest + '/' + fileName)) { + return false + } + return true + } catch (e) { + console.log(e) + return false + } + } + + async moveDirIsAllowed (src: string, dest: string) { + try { + src = this.normalize(src) + dest = this.normalize(dest) + src = this.limitPluginScope(src) + dest = this.limitPluginScope(dest) + await this._handleExists(src, `Cannot move ${src}. Path does not exist.`) + await this._handleExists(dest, `Cannot move content into ${dest}. Path does not exist.`) + await this._handleIsDir(src, `Cannot move ${src}. Path is not directory.`) + await this._handleIsDir(dest, `Cannot move content into ${dest}. Path is not directory.`) + const dirName = helper.extractNameFromKey(src) + const provider = this.fileProviderOf(src) + + if (await this.exists(dest + '/' + dirName) || src === dest) { + return false + } + + if (provider.isSubDirectory(src, dest)) { + this.call('notification', 'toast', recursivePasteToastMsg()) + return false + } + return true + } catch (e) { + console.log(e) + return false + } + } + /** * Moves a file to a new folder * @param {string} src path of the source file * @param {string} dest path of the destrination file * @returns {void} */ - - async moveFile(src: string, dest: string) { + + async moveFile(src: string, dest: string) { try { src = this.normalize(src) dest = this.normalize(dest) @@ -895,9 +979,9 @@ class FileManager extends Plugin { await this._handleIsFile(src, `Cannot move ${src}. Path is not a file.`) await this._handleIsDir(dest, `Cannot move content into ${dest}. Path is not directory.`) const fileName = helper.extractNameFromKey(src) - + if (await this.exists(dest + '/' + fileName)) { - throw createError({ code: 'EEXIST', message: `Cannot move ${src}. File already exists at destination ${dest}`}) + throw createError({ code: 'EEXIST', message: `Cannot move ${src}. File already exists at destination ${dest}` }) } await this.copyFile(src, dest, fileName) await this.remove(src) @@ -912,7 +996,7 @@ class FileManager extends Plugin { * @param {string} dest path of the destination folder * @returns {void} */ - + async moveDir(src: string, dest: string) { try { src = this.normalize(src) @@ -925,9 +1009,15 @@ class FileManager extends Plugin { await this._handleIsDir(dest, `Cannot move content into ${dest}. Path is not directory.`) const dirName = helper.extractNameFromKey(src) if (await this.exists(dest + '/' + dirName) || src === dest) { - throw createError({ code: 'EEXIST', message: `Cannot move ${src}. Folder already exists at destination ${dest}`}) + throw createError({ code: 'EEXIST', message: `Cannot move ${src}. Folder already exists at destination ${dest}` }) } - await this.copyDir(src, dest, dirName) + const provider = this.fileProviderOf(src) + + if (provider.isSubDirectory(src, dest)) { + this.call('notification', 'toast', recursivePasteToastMsg()) + return false + } + await this.inDepthCopy(src, dest, dirName) await this.remove(src) } catch (e) { diff --git a/apps/remix-ide/src/app/files/fileSystem.ts b/apps/remix-ide/src/app/files/fileSystem.ts index 80b7663680..80840f617f 100644 --- a/apps/remix-ide/src/app/files/fileSystem.ts +++ b/apps/remix-ide/src/app/files/fileSystem.ts @@ -1,71 +1,71 @@ export class fileSystem { - name: string - enabled: boolean - available: boolean - fs: any - fsCallBack: any; - hasWorkSpaces: boolean - loaded: boolean - load: () => Promise - test: () => Promise + name: string + enabled: boolean + available: boolean + fs: any + fsCallBack: any; + hasWorkSpaces: boolean + loaded: boolean + load: () => Promise + test: () => Promise - constructor() { - this.available = false - this.enabled = false - this.hasWorkSpaces = false - this.loaded = false - } + constructor() { + this.available = false + this.enabled = false + this.hasWorkSpaces = false + this.loaded = false + } - checkWorkspaces = async () => { - try { - await this.fs.stat('.workspaces') - this.hasWorkSpaces = true - } catch (e) { + checkWorkspaces = async () => { + try { + await this.fs.stat('.workspaces') + this.hasWorkSpaces = true + } catch (e) { - } } + } - set = async () => { - const w = (window as any) - if (!this.loaded) return false - w.remixFileSystem = this.fs - w.remixFileSystem.name = this.name - w.remixFileSystemCallback = this.fsCallBack - return true - } + set = async () => { + const w = (window as any) + if (!this.loaded) return false + w.remixFileSystem = this.fs + w.remixFileSystem.name = this.name + w.remixFileSystemCallback = this.fsCallBack + return true + } } export class fileSystems { - fileSystems: Record - constructor() { - this.fileSystems = {} - } + fileSystems: Record + constructor() { + this.fileSystems = {} + } - addFileSystem = async (fs: fileSystem): Promise => { - try { - this.fileSystems[fs.name] = fs - await fs.test() && await fs.load() - console.log(fs.name + ' is loaded...') - return true - } catch (e) { - console.log(fs.name + ' not available...') - return false - } + addFileSystem = async (fs: fileSystem): Promise => { + try { + this.fileSystems[fs.name] = fs + await fs.test() && await fs.load() + console.log(fs.name + ' is loaded...') + return true + } catch (e) { + console.log(fs.name + ' not available...') + return false } - /** + } + /** * sets filesystem using list as fallback * @param {string[]} names * @returns {Promise} */ - setFileSystem = async (filesystems?: fileSystem[]): Promise => { - for (const fs of filesystems) { - if (fs && this.fileSystems[fs.name]) { - const result = await this.fileSystems[fs.name].set() - if (result) return this.fileSystems[fs.name] - } - } - return null + setFileSystem = async (filesystems?: fileSystem[]): Promise => { + for (const fs of filesystems) { + if (fs && this.fileSystems[fs.name]) { + const result = await this.fileSystems[fs.name].set() + if (result) return this.fileSystems[fs.name] + } } + return null + } } diff --git a/apps/remix-ide/src/app/files/filesystems/fileSystemUtility.ts b/apps/remix-ide/src/app/files/filesystems/fileSystemUtility.ts index 538679c671..9fc716b5c1 100644 --- a/apps/remix-ide/src/app/files/filesystems/fileSystemUtility.ts +++ b/apps/remix-ide/src/app/files/filesystems/fileSystemUtility.ts @@ -3,189 +3,189 @@ import JSZip from "jszip" import { fileSystem } from "../fileSystem" const _paq = window._paq = window._paq || [] export class fileSystemUtility { - migrate = async (fsFrom: fileSystem, fsTo: fileSystem) => { - try { - await fsFrom.checkWorkspaces() - await fsTo.checkWorkspaces() - - if (fsTo.hasWorkSpaces) { - console.log(`${fsTo.name} already has files`) - return true - } - - if (!fsFrom.hasWorkSpaces) { - console.log('no files to migrate') - return true - } - - const fromFiles = await this.copyFolderToJson('/', null, null, fsFrom.fs) - await this.populateWorkspace(fromFiles, fsTo.fs) - const toFiles = await this.copyFolderToJson('/', null, null, fsTo.fs) - - if (hashMessage(JSON.stringify(toFiles)) === hashMessage(JSON.stringify(fromFiles))) { - console.log('file migration successful') - return true - } else { - _paq.push(['trackEvent', 'Migrate', 'error', 'hash mismatch']) - console.log('file migration failed falling back to ' + fsFrom.name) - fsTo.loaded = false - return false - } - } catch (err) { - console.log(err) - _paq.push(['trackEvent', 'Migrate', 'error', err && err.message]) - console.log('file migration failed falling back to ' + fsFrom.name) - fsTo.loaded = false - return false - } + migrate = async (fsFrom: fileSystem, fsTo: fileSystem) => { + try { + await fsFrom.checkWorkspaces() + await fsTo.checkWorkspaces() + + if (fsTo.hasWorkSpaces) { + console.log(`${fsTo.name} already has files`) + return true + } + + if (!fsFrom.hasWorkSpaces) { + console.log('no files to migrate') + return true + } + + const fromFiles = await this.copyFolderToJson('/', null, null, fsFrom.fs) + await this.populateWorkspace(fromFiles, fsTo.fs) + const toFiles = await this.copyFolderToJson('/', null, null, fsTo.fs) + + if (hashMessage(JSON.stringify(toFiles)) === hashMessage(JSON.stringify(fromFiles))) { + console.log('file migration successful') + return true + } else { + _paq.push(['trackEvent', 'Migrate', 'error', 'hash mismatch']) + console.log('file migration failed falling back to ' + fsFrom.name) + fsTo.loaded = false + return false + } + } catch (err) { + console.log(err) + _paq.push(['trackEvent', 'Migrate', 'error', err && err.message]) + console.log('file migration failed falling back to ' + fsFrom.name) + fsTo.loaded = false + return false } - - downloadBackup = async (fs: fileSystem) => { - try { - const zip = new JSZip() - zip.file("readme.txt", "This is a Remix backup file.\nThis zip should be used by the restore backup tool in Remix.\nThe .workspaces directory contains your workspaces.") - await fs.checkWorkspaces() - await this.copyFolderToJson('/', null, null, fs.fs, ({ path, content }) => { - zip.file(path, content) - }) - const blob = await zip.generateAsync({ type: 'blob' }) - const today = new Date() - const date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate() - const time = today.getHours() + 'h' + today.getMinutes() + 'min' - this.saveAs(blob, `remix-backup-at-${time}-${date}.zip`) - _paq.push(['trackEvent','Backup','download','preload']) - } catch (err) { - _paq.push(['trackEvent','Backup','error',err && err.message]) - console.log(err) - } + } + + downloadBackup = async (fs: fileSystem) => { + try { + const zip = new JSZip() + zip.file("readme.txt", "This is a Remix backup file.\nThis zip should be used by the restore backup tool in Remix.\nThe .workspaces directory contains your workspaces.") + await fs.checkWorkspaces() + await this.copyFolderToJson('/', null, null, fs.fs, ({ path, content }) => { + zip.file(path, content) + }) + const blob = await zip.generateAsync({ type: 'blob' }) + const today = new Date() + const date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate() + const time = today.getHours() + 'h' + today.getMinutes() + 'min' + this.saveAs(blob, `remix-backup-at-${time}-${date}.zip`) + _paq.push(['trackEvent','Backup','download','preload']) + } catch (err) { + _paq.push(['trackEvent','Backup','error',err && err.message]) + console.log(err) } - - populateWorkspace = async (json, fs) => { - for (const item in json) { - const isFolder = json[item].content === undefined - if (isFolder) { - await this.createDir(item, fs) - await this.populateWorkspace(json[item].children, fs) - } else { - await fs.writeFile(item, json[item].content, 'utf8') - } - } + } + + populateWorkspace = async (json, fs) => { + for (const item in json) { + const isFolder = json[item].content === undefined + if (isFolder) { + await this.createDir(item, fs) + await this.populateWorkspace(json[item].children, fs) + } else { + await fs.writeFile(item, json[item].content, 'utf8') + } } + } - /** + /** * copy the folder recursively * @param {string} path is the folder to be copied over * @param {Function} visitFile is a function called for each visited files * @param {Function} visitFolder is a function called for each visited folders */ - copyFolderToJson = async (path, visitFile, visitFolder, fs, cb = null) => { - visitFile = visitFile || (() => { }) - visitFolder = visitFolder || (() => { }) - return await this._copyFolderToJsonInternal(path, visitFile, visitFolder, fs, cb) - } + copyFolderToJson = async (path, visitFile, visitFolder, fs, cb = null) => { + visitFile = visitFile || (() => { }) + visitFolder = visitFolder || (() => { }) + return await this._copyFolderToJsonInternal(path, visitFile, visitFolder, fs, cb) + } - /** + /** * copy the folder recursively (internal use) * @param {string} path is the folder to be copied over * @param {Function} visitFile is a function called for each visited files * @param {Function} visitFolder is a function called for each visited folders */ - async _copyFolderToJsonInternal(path, visitFile, visitFolder, fs, cb) { - visitFile = visitFile || function () { /* do nothing. */ } - visitFolder = visitFolder || function () { /* do nothing. */ } - - const json = {} - // path = this.removePrefix(path) - if (await fs.exists(path)) { - const items = await fs.readdir(path) - visitFolder({ path }) - if (items.length !== 0) { - for (const item of items) { - const file: any = {} - const curPath = `${path}${path.endsWith('/') ? '' : '/'}${item}` - if ((await fs.stat(curPath)).isDirectory()) { - file.children = await this._copyFolderToJsonInternal(curPath, visitFile, visitFolder, fs, cb) - } else { - file.content = await fs.readFile(curPath, 'utf8') - if (cb) cb({ path: curPath, content: file.content }) - visitFile({ path: curPath, content: file.content }) - - } - json[curPath] = file - } - } - } - return json - } - - createDir = async (path, fs) => { - const paths = path.split('/') - if (paths.length && paths[0] === '') paths.shift() - let currentCheck = '' - for (const value of paths) { - currentCheck = currentCheck + (currentCheck ? '/' : '') + value - if (!await fs.exists(currentCheck)) { - await fs.mkdir(currentCheck) - } + async _copyFolderToJsonInternal(path, visitFile, visitFolder, fs, cb) { + visitFile = visitFile || function () { /* do nothing. */ } + visitFolder = visitFolder || function () { /* do nothing. */ } + + const json = {} + // path = this.removePrefix(path) + if (await fs.exists(path)) { + const items = await fs.readdir(path) + visitFolder({ path }) + if (items.length !== 0) { + for (const item of items) { + const file: any = {} + const curPath = `${path}${path.endsWith('/') ? '' : '/'}${item}` + if ((await fs.stat(curPath)).isDirectory()) { + file.children = await this._copyFolderToJsonInternal(curPath, visitFile, visitFolder, fs, cb) + } else { + file.content = await fs.readFile(curPath, 'utf8') + if (cb) cb({ path: curPath, content: file.content }) + visitFile({ path: curPath, content: file.content }) + + } + json[curPath] = file } + } } - - saveAs = (blob, name) => { - const node = document.createElement('a') - node.download = name - node.rel = 'noopener' - node.href = URL.createObjectURL(blob) - setTimeout(function () { URL.revokeObjectURL(node.href) }, 4E4) // 40s - setTimeout(function () { - try { - node.dispatchEvent(new MouseEvent('click')) - } catch (e) { - const evt = document.createEvent('MouseEvents') - evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, - 20, false, false, false, false, 0, null) - node.dispatchEvent(evt) - } - }, 0) // 40s + return json + } + + createDir = async (path, fs) => { + const paths = path.split('/') + if (paths.length && paths[0] === '') paths.shift() + let currentCheck = '' + for (const value of paths) { + currentCheck = currentCheck + (currentCheck ? '/' : '') + value + if (!await fs.exists(currentCheck)) { + await fs.mkdir(currentCheck) + } } + } + + saveAs = (blob, name) => { + const node = document.createElement('a') + node.download = name + node.rel = 'noopener' + node.href = URL.createObjectURL(blob) + setTimeout(function () { URL.revokeObjectURL(node.href) }, 4E4) // 40s + setTimeout(function () { + try { + node.dispatchEvent(new MouseEvent('click')) + } catch (e) { + const evt = document.createEvent('MouseEvents') + evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, + 20, false, false, false, false, 0, null) + node.dispatchEvent(evt) + } + }, 0) // 40s + } } /* eslint-disable no-template-curly-in-string */ export const migrationTestData = { - '.workspaces': { + '.workspaces': { + children: { + '.workspaces/default_workspace': { children: { - '.workspaces/default_workspace': { - children: { - '.workspaces/default_workspace/README.txt': { - content: 'TEST README' - } - } - }, - '.workspaces/emptyspace': { + '.workspaces/default_workspace/README.txt': { + content: 'TEST README' + } + } + }, + '.workspaces/emptyspace': { - }, - '.workspaces/workspace_test': { + }, + '.workspaces/workspace_test': { + children: { + '.workspaces/workspace_test/TEST_README.txt': { + content: 'TEST README' + }, + '.workspaces/workspace_test/test_contracts': { + children: { + '.workspaces/workspace_test/test_contracts/1_Storage.sol': { + content: 'testing' + }, + '.workspaces/workspace_test/test_contracts/artifacts': { children: { - '.workspaces/workspace_test/TEST_README.txt': { - content: 'TEST README' - }, - '.workspaces/workspace_test/test_contracts': { - children: { - '.workspaces/workspace_test/test_contracts/1_Storage.sol': { - content: 'testing' - }, - '.workspaces/workspace_test/test_contracts/artifacts': { - children: { - '.workspaces/workspace_test/test_contracts/artifacts/Storage_metadata.json': { - content: '{ "test": "data" }' - } - } - } - } - } + '.workspaces/workspace_test/test_contracts/artifacts/Storage_metadata.json': { + content: '{ "test": "data" }' + } } + } } + } } + } } + } } \ No newline at end of file diff --git a/apps/remix-ide/src/app/files/filesystems/indexedDB.ts b/apps/remix-ide/src/app/files/filesystems/indexedDB.ts index 5d20a52061..aae0d6a5eb 100644 --- a/apps/remix-ide/src/app/files/filesystems/indexedDB.ts +++ b/apps/remix-ide/src/app/files/filesystems/indexedDB.ts @@ -2,90 +2,90 @@ import LightningFS from "@isomorphic-git/lightning-fs" import { fileSystem } from "../fileSystem" export class IndexedDBStorage extends LightningFS { - base: LightningFS.PromisifedFS - addSlash: (file: string) => string - extended: { exists: (path: string) => Promise; rmdir: (path: any) => Promise; readdir: (path: any) => Promise; unlink: (path: any) => Promise; mkdir: (path: any) => Promise; readFile: (path: any, options: any) => Promise; rename: (from: any, to: any) => Promise; writeFile: (path: any, content: any, options: any) => Promise; stat: (path: any) => Promise; init(name: string, opt?: LightningFS.FSConstructorOptions): void; activate(): Promise; deactivate(): Promise; lstat(filePath: string): Promise; readlink(filePath: string): Promise; symlink(target: string, filePath: string): Promise } - constructor(name: string) { - super(name) - this.addSlash = (file) => { - if (!file.startsWith('/')) file = '/' + file - return file - } - this.base = this.promises - this.extended = { - ...this.promises, - exists: async (path: string) => { - return new Promise((resolve) => { - this.base.stat(this.addSlash(path)).then(() => resolve(true)).catch(() => resolve(false)) - }) - }, - rmdir: async (path) => { - return this.base.rmdir(this.addSlash(path)) - }, - readdir: async (path) => { - return this.base.readdir(this.addSlash(path)) - }, - unlink: async (path) => { - return this.base.unlink(this.addSlash(path)) - }, - mkdir: async (path) => { - return this.base.mkdir(this.addSlash(path)) - }, - readFile: async (path, options) => { - return this.base.readFile(this.addSlash(path), options) - }, - rename: async (from, to) => { - return this.base.rename(this.addSlash(from), this.addSlash(to)) - }, - writeFile: async (path, content, options) => { - return this.base.writeFile(this.addSlash(path), content, options) - }, - stat: async (path) => { - return this.base.stat(this.addSlash(path)) - } - } + base: LightningFS.PromisifedFS + addSlash: (file: string) => string + extended: { exists: (path: string) => Promise; rmdir: (path: any) => Promise; readdir: (path: any) => Promise; unlink: (path: any) => Promise; mkdir: (path: any) => Promise; readFile: (path: any, options: any) => Promise; rename: (from: any, to: any) => Promise; writeFile: (path: any, content: any, options: any) => Promise; stat: (path: any) => Promise; init(name: string, opt?: LightningFS.FSConstructorOptions): void; activate(): Promise; deactivate(): Promise; lstat(filePath: string): Promise; readlink(filePath: string): Promise; symlink(target: string, filePath: string): Promise } + constructor(name: string) { + super(name) + this.addSlash = (file) => { + if (!file.startsWith('/')) file = '/' + file + return file } + this.base = this.promises + this.extended = { + ...this.promises, + exists: async (path: string) => { + return new Promise((resolve) => { + this.base.stat(this.addSlash(path)).then(() => resolve(true)).catch(() => resolve(false)) + }) + }, + rmdir: async (path) => { + return this.base.rmdir(this.addSlash(path)) + }, + readdir: async (path) => { + return this.base.readdir(this.addSlash(path)) + }, + unlink: async (path) => { + return this.base.unlink(this.addSlash(path)) + }, + mkdir: async (path) => { + return this.base.mkdir(this.addSlash(path)) + }, + readFile: async (path, options) => { + return this.base.readFile(this.addSlash(path), options) + }, + rename: async (from, to) => { + return this.base.rename(this.addSlash(from), this.addSlash(to)) + }, + writeFile: async (path, content, options) => { + return this.base.writeFile(this.addSlash(path), content, options) + }, + stat: async (path) => { + return this.base.stat(this.addSlash(path)) + } + } + } } export class indexedDBFileSystem extends fileSystem { - constructor() { - super() - this.name = 'indexedDB' - } + constructor() { + super() + this.name = 'indexedDB' + } - load = async () => { - return new Promise((resolve, reject) => { - try { - const fs = new IndexedDBStorage('RemixFileSystem') - fs.init('RemixFileSystem') - this.fs = fs.extended - this.fsCallBack = fs - this.loaded = true - resolve(true) - } catch (e) { - reject(e) - } - }) - } + load = async () => { + return new Promise((resolve, reject) => { + try { + const fs = new IndexedDBStorage('RemixFileSystem') + fs.init('RemixFileSystem') + this.fs = fs.extended + this.fsCallBack = fs + this.loaded = true + resolve(true) + } catch (e) { + reject(e) + } + }) + } - test = async () => { - return new Promise((resolve, reject) => { - if (!window.indexedDB) { - this.available = false - reject('No indexedDB on window') - } - const request = window.indexedDB.open("RemixTestDataBase"); - request.onerror = () => { - this.available = false - reject('Error creating test database') - }; - request.onsuccess = () => { - window.indexedDB.deleteDatabase("RemixTestDataBase"); - this.available = true - resolve(true) - }; - }) - } + test = async () => { + return new Promise((resolve, reject) => { + if (!window.indexedDB) { + this.available = false + reject('No indexedDB on window') + } + const request = window.indexedDB.open("RemixTestDataBase"); + request.onerror = () => { + this.available = false + reject('Error creating test database') + }; + request.onsuccess = () => { + window.indexedDB.deleteDatabase("RemixTestDataBase"); + this.available = true + resolve(true) + }; + }) + } } \ No newline at end of file diff --git a/apps/remix-ide/src/app/files/filesystems/localStorage.ts b/apps/remix-ide/src/app/files/filesystems/localStorage.ts index 8346a37976..d99c3ae296 100644 --- a/apps/remix-ide/src/app/files/filesystems/localStorage.ts +++ b/apps/remix-ide/src/app/files/filesystems/localStorage.ts @@ -2,56 +2,56 @@ import { fileSystem } from "../fileSystem"; export class localStorageFS extends fileSystem { - constructor() { - super() - this.name = 'localstorage' - } - load = async () => { - const me = this - return new Promise((resolve, reject) => { - try { - const w = window as any - w.BrowserFS.install(window) - w.BrowserFS.configure({ - fs: 'LocalStorage' - }, async function (e) { - if (e) { - console.log('BrowserFS Error: ' + e) - reject(e) - } else { - me.fs = { ...window.require('fs') } - me.fsCallBack = window.require('fs') - me.fs.readdir = me.fs.readdirSync - me.fs.readFile = me.fs.readFileSync - me.fs.writeFile = me.fs.writeFileSync - me.fs.stat = me.fs.statSync - me.fs.unlink = me.fs.unlinkSync - me.fs.rmdir = me.fs.rmdirSync - me.fs.mkdir = me.fs.mkdirSync - me.fs.rename = me.fs.renameSync - me.fs.exists = me.fs.existsSync - me.loaded = true - resolve(true) - } - }) - } catch (e) { - console.log('BrowserFS is not ready!') - reject(e) - } + constructor() { + super() + this.name = 'localstorage' + } + load = async () => { + const me = this + return new Promise((resolve, reject) => { + try { + const w = window as any + w.BrowserFS.install(window) + w.BrowserFS.configure({ + fs: 'LocalStorage' + }, async function (e) { + if (e) { + console.log('BrowserFS Error: ' + e) + reject(e) + } else { + me.fs = { ...window.require('fs') } + me.fsCallBack = window.require('fs') + me.fs.readdir = me.fs.readdirSync + me.fs.readFile = me.fs.readFileSync + me.fs.writeFile = me.fs.writeFileSync + me.fs.stat = me.fs.statSync + me.fs.unlink = me.fs.unlinkSync + me.fs.rmdir = me.fs.rmdirSync + me.fs.mkdir = me.fs.mkdirSync + me.fs.rename = me.fs.renameSync + me.fs.exists = me.fs.existsSync + me.loaded = true + resolve(true) + } }) - } + } catch (e) { + console.log('BrowserFS is not ready!') + reject(e) + } + }) + } - test = async () => { - return new Promise((resolve, reject) => { - const test = 'test'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - resolve(true) - } catch(e) { - reject(e) - } - }) - } + test = async () => { + return new Promise((resolve, reject) => { + const test = 'test'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + resolve(true) + } catch(e) { + reject(e) + } + }) + } } \ No newline at end of file diff --git a/apps/remix-ide/src/app/panels/layout.ts b/apps/remix-ide/src/app/panels/layout.ts index a88fb97584..a152efc72e 100644 --- a/apps/remix-ide/src/app/panels/layout.ts +++ b/apps/remix-ide/src/app/panels/layout.ts @@ -6,7 +6,7 @@ import { QueryParams } from '@remix-project/remix-lib' const profile: Profile = { name: 'layout', description: 'layout', - methods: ['minimize', 'maximiseSidePanel', 'resetSidePanel'] + methods: ['minimize', 'maximiseSidePanel', 'resetSidePanel', 'maximizeTerminal'] } interface panelState { @@ -61,9 +61,9 @@ export class Layout extends Plugin { }) this.on('manager', 'activate', (profile: Profile) => { switch (profile.name) { - case 'filePanel': - this.call('menuicons', 'select', 'filePanel') - break + case 'filePanel': + this.call('menuicons', 'select', 'filePanel') + break } }) this.on('sidePanel', 'focusChanged', async (name) => { @@ -109,6 +109,12 @@ export class Layout extends Plugin { this.maximised[current] = true } + async maximizeTerminal() { + this.panels.terminal.minimized = false + this.event.emit('change', this.panels) + this.emit('change', this.panels) + } + async resetSidePanel () { this.event.emit('resetsidepanel') const current = await this.call('sidePanel', 'currentFocus') diff --git a/apps/remix-ide/src/app/plugins/code-format.ts b/apps/remix-ide/src/app/plugins/code-format.ts index 1d74cff422..04266c1615 100644 --- a/apps/remix-ide/src/app/plugins/code-format.ts +++ b/apps/remix-ide/src/app/plugins/code-format.ts @@ -8,279 +8,279 @@ import toml from 'toml' import { filePathFilter, AnyFilter } from '@jsdevtools/file-path-filter' const profile = { - name: 'codeFormatter', - desciption: 'prettier plugin for Remix', - methods: ['format'], - events: [''], - version: '0.0.1' + name: 'codeFormatter', + desciption: 'prettier plugin for Remix', + methods: ['format'], + events: [''], + version: '0.0.1' } const defaultOptions = { - "overrides": [ - { - "files": "*.sol", - "options": { - "printWidth": 80, - "tabWidth": 4, - "useTabs": false, - "singleQuote": false, - "bracketSpacing": false, - } - }, - { - "files": "*.yml", - "options": { - } - }, - { - "files": "*.yaml", - "options": { - } - }, - { - "files": "*.toml", - "options": { - } - }, - { - "files": "*.json", - "options": { - } - }, - { - "files": "*.js", - "options": { - } - }, - { - "files": "*.ts", - "options": { - } - } - ] + "overrides": [ + { + "files": "*.sol", + "options": { + "printWidth": 80, + "tabWidth": 4, + "useTabs": false, + "singleQuote": false, + "bracketSpacing": false, + } + }, + { + "files": "*.yml", + "options": { + } + }, + { + "files": "*.yaml", + "options": { + } + }, + { + "files": "*.toml", + "options": { + } + }, + { + "files": "*.json", + "options": { + } + }, + { + "files": "*.js", + "options": { + } + }, + { + "files": "*.ts", + "options": { + } + } + ] } export class CodeFormat extends Plugin { - prettier: any - ts: any - babel: any - espree: any - yml: any - sol: any + prettier: any + ts: any + babel: any + espree: any + yml: any + sol: any - constructor() { - super(profile) - } + constructor() { + super(profile) + } - async format(file: string) { + async format(file: string) { - // lazy load - if (!this.prettier) { - this.prettier = await import('prettier/standalone') - this.ts = await import('prettier/parser-typescript') - this.babel = await import('prettier/parser-babel') - this.espree = await import('prettier/parser-espree') - this.yml = await import('prettier/parser-yaml') - } + // lazy load + if (!this.prettier) { + this.prettier = await import('prettier/standalone') + this.ts = await import('prettier/parser-typescript') + this.babel = await import('prettier/parser-babel') + this.espree = await import('prettier/parser-espree') + this.yml = await import('prettier/parser-yaml') + } - try { - const content = await this.call('fileManager', 'readFile', file) - if (!content) return - let parserName = '' - let options: Options = { - } - switch (path.extname(file)) { - case '.sol': - parserName = 'solidity-parse' - break - case '.ts': - parserName = 'typescript' - options = { - ...options, - trailingComma: 'all', - semi: false, - singleQuote: true, - quoteProps: 'as-needed', - bracketSpacing: true, - arrowParens: 'always', - } - break - case '.js': - parserName = "espree" - options = { - ...options, - semi: false, - singleQuote: true, - } - break - case '.json': - parserName = 'json' - break - case '.yml': - parserName = 'yaml' - break - case '.yaml': - parserName = 'yaml' - break - } + try { + const content = await this.call('fileManager', 'readFile', file) + if (!content) return + let parserName = '' + let options: Options = { + } + switch (path.extname(file)) { + case '.sol': + parserName = 'solidity-parse' + break + case '.ts': + parserName = 'typescript' + options = { + ...options, + trailingComma: 'all', + semi: false, + singleQuote: true, + quoteProps: 'as-needed', + bracketSpacing: true, + arrowParens: 'always', + } + break + case '.js': + parserName = "espree" + options = { + ...options, + semi: false, + singleQuote: true, + } + break + case '.json': + parserName = 'json' + break + case '.yml': + parserName = 'yaml' + break + case '.yaml': + parserName = 'yaml' + break + } - if (file === '.prettierrc') { - parserName = 'json' - } + if (file === '.prettierrc') { + parserName = 'json' + } - const possibleFileNames = [ - '.prettierrc', - '.prettierrc.json', - '.prettierrc.yaml', - '.prettierrc.yml', - '.prettierrc.toml', - '.prettierrc.js', - '.prettierrc.cjs', - 'prettier.config.js', - 'prettier.config.cjs', - '.prettierrc.json5', - ] + const possibleFileNames = [ + '.prettierrc', + '.prettierrc.json', + '.prettierrc.yaml', + '.prettierrc.yml', + '.prettierrc.toml', + '.prettierrc.js', + '.prettierrc.cjs', + 'prettier.config.js', + 'prettier.config.cjs', + '.prettierrc.json5', + ] - const prettierConfigFile = await findAsync(possibleFileNames, async (fileName) => { - const exists = await this.call('fileManager', 'exists', fileName) - return exists - }) + const prettierConfigFile = await findAsync(possibleFileNames, async (fileName) => { + const exists = await this.call('fileManager', 'exists', fileName) + return exists + }) - let parsed = null - if (prettierConfigFile) { - let prettierConfig = await this.call('fileManager', 'readFile', prettierConfigFile) - if (prettierConfig) { - if (prettierConfigFile.endsWith('.yaml') || prettierConfigFile.endsWith('.yml')) { - try { - parsed = yaml.load(prettierConfig) - } catch (e) { - // do nothing - } - } else if (prettierConfigFile.endsWith('.toml')) { - try { - parsed = toml.parse(prettierConfig) - } catch (e) { - // do nothing - } - } else if (prettierConfigFile.endsWith('.json') || prettierConfigFile.endsWith('.json5')) { - try { - parsed = JSON.parse(prettierConfig) - } catch (e) { - // do nothing - } - } else if (prettierConfigFile === '.prettierrc') { - try { - parsed = JSON.parse(prettierConfig) - } catch (e) { - // do nothing - } - if (!parsed) { - try { - parsed = yaml.load(prettierConfig) - } catch (e) { - // do nothing - } - } - } else if (prettierConfigFile.endsWith('.js') || prettierConfigFile.endsWith('.cjs')) { - // remove any comments - prettierConfig = prettierConfig.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '') - // add quotes to keys - prettierConfig = prettierConfig.replace(/([a-zA-Z0-9_]+)(\s*):/g, '"$1"$2:') - // remove comma from last key - prettierConfig = prettierConfig.replace(/,(\s*})/g, '$1') - // remove any semi-colons - prettierConfig = prettierConfig.replace(/;/g, '') - // convert single quotes to double quotes - prettierConfig = prettierConfig.replace(/'/g, '"') - try { - parsed = JSON.parse(prettierConfig.replace('module.exports = ', '').replace('module.exports=', '')) - } catch (e) { - // do nothing - } - } - } - } else { - parsed = defaultOptions - await this.call('fileManager', 'writeFile', '.prettierrc.json', JSON.stringify(parsed, null, 2)) - await this.call('notification', 'toast', 'A prettier config file has been created in the workspace.') + let parsed = null + if (prettierConfigFile) { + let prettierConfig = await this.call('fileManager', 'readFile', prettierConfigFile) + if (prettierConfig) { + if (prettierConfigFile.endsWith('.yaml') || prettierConfigFile.endsWith('.yml')) { + try { + parsed = yaml.load(prettierConfig) + } catch (e) { + // do nothing } - - if (!parsed && prettierConfigFile) { - this.call('notification', 'toast', `Error parsing prettier config file: ${prettierConfigFile}`) + } else if (prettierConfigFile.endsWith('.toml')) { + try { + parsed = toml.parse(prettierConfig) + } catch (e) { + // do nothing + } + } else if (prettierConfigFile.endsWith('.json') || prettierConfigFile.endsWith('.json5')) { + try { + parsed = JSON.parse(prettierConfig) + } catch (e) { + // do nothing + } + } else if (prettierConfigFile === '.prettierrc') { + try { + parsed = JSON.parse(prettierConfig) + } catch (e) { + // do nothing + } + if (!parsed) { + try { + parsed = yaml.load(prettierConfig) + } catch (e) { + // do nothing + } + } + } else if (prettierConfigFile.endsWith('.js') || prettierConfigFile.endsWith('.cjs')) { + // remove any comments + prettierConfig = prettierConfig.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '') + // add quotes to keys + prettierConfig = prettierConfig.replace(/([a-zA-Z0-9_]+)(\s*):/g, '"$1"$2:') + // remove comma from last key + prettierConfig = prettierConfig.replace(/,(\s*})/g, '$1') + // remove any semi-colons + prettierConfig = prettierConfig.replace(/;/g, '') + // convert single quotes to double quotes + prettierConfig = prettierConfig.replace(/'/g, '"') + try { + parsed = JSON.parse(prettierConfig.replace('module.exports = ', '').replace('module.exports=', '')) + } catch (e) { + // do nothing } + } + } + } else { + parsed = defaultOptions + await this.call('fileManager', 'writeFile', '.prettierrc.json', JSON.stringify(parsed, null, 2)) + await this.call('notification', 'toast', 'A prettier config file has been created in the workspace.') + } + if (!parsed && prettierConfigFile) { + this.call('notification', 'toast', `Error parsing prettier config file: ${prettierConfigFile}`) + } - // merge options - if (parsed) { - options = { - ...options, - ...parsed, - } - } - // search for overrides - if (parsed && parsed.overrides) { - const override = parsed.overrides.find((override) => { - if (override.files) { - const pathFilter: AnyFilter = {} - pathFilter.include = setGlobalExpression(override.files) - const filteredFiles = [file] - .filter(filePathFilter(pathFilter)) - if (filteredFiles.length) { - return true - } - } - }) - const validParsers = ['typescript', 'babel', 'espree', 'solidity-parse', 'json', 'yaml', 'solidity-parse'] - if (override && override.options && override.options.parser) { - if (validParsers.includes(override.options.parser)) { - parserName = override.options.parser - } else { - this.call('notification', 'toast', `Invalid parser: ${override.options.parser}! Valid options are ${validParsers.join(', ')}`) - } - delete override.options.parser - } + // merge options + if (parsed) { + options = { + ...options, + ...parsed, + } + } - if (override) { - options = { - ...options, - ...override.options, - } - } + // search for overrides + if (parsed && parsed.overrides) { + const override = parsed.overrides.find((override) => { + if (override.files) { + const pathFilter: AnyFilter = {} + pathFilter.include = setGlobalExpression(override.files) + const filteredFiles = [file] + .filter(filePathFilter(pathFilter)) + if (filteredFiles.length) { + return true } + } + }) + const validParsers = ['typescript', 'babel', 'espree', 'solidity-parse', 'json', 'yaml', 'solidity-parse'] + if (override && override.options && override.options.parser) { + if (validParsers.includes(override.options.parser)) { + parserName = override.options.parser + } else { + this.call('notification', 'toast', `Invalid parser: ${override.options.parser}! Valid options are ${validParsers.join(', ')}`) + } + delete override.options.parser + } - - const result = this.prettier.format(content, { - plugins: [sol as any, this.ts, this.babel, this.espree, this.yml], - parser: parserName, - ...options - }) - await this.call('fileManager', 'writeFile', file, result) - } catch (e) { - // do nothing + if (override) { + options = { + ...options, + ...override.options, + } } + } + + + const result = this.prettier.format(content, { + plugins: [sol as any, this.ts, this.babel, this.espree, this.yml], + parser: parserName, + ...options + }) + await this.call('fileManager', 'writeFile', file, result) + } catch (e) { + // do nothing } + } } //*.sol, **/*.txt, contracts/* const setGlobalExpression = (paths: string) => { - const results = [] - paths.split(',').forEach(path => { - path = path.trim() - if (path.startsWith('*.')) path = path.replace(/(\*\.)/g, '**/*.') - if (path.endsWith('/*') && !path.endsWith('/**/*')) - path = path.replace(/(\*)/g, '**/*.*') - results.push(path) - }) - return results + const results = [] + paths.split(',').forEach(path => { + path = path.trim() + if (path.startsWith('*.')) path = path.replace(/(\*\.)/g, '**/*.') + if (path.endsWith('/*') && !path.endsWith('/**/*')) + path = path.replace(/(\*)/g, '**/*.*') + results.push(path) + }) + return results } async function findAsync(arr, asyncCallback) { - const promises = arr.map(asyncCallback); - const results = await Promise.all(promises); - const index = results.findIndex(result => result); - return arr[index]; + const promises = arr.map(asyncCallback); + const results = await Promise.all(promises); + const index = results.findIndex(result => result); + return arr[index]; } diff --git a/apps/remix-ide/src/app/plugins/code-format/index.ts b/apps/remix-ide/src/app/plugins/code-format/index.ts index 777009974c..32f785574c 100644 --- a/apps/remix-ide/src/app/plugins/code-format/index.ts +++ b/apps/remix-ide/src/app/plugins/code-format/index.ts @@ -8,54 +8,54 @@ import { parse } from './parser' // https://prettier.io/docs/en/plugins.html#languages // https://github.com/ikatyang/linguist-languages/blob/master/data/Solidity.json const languages = [ - { - linguistLanguageId: 237469032, - name: 'Solidity', - type: 'programming', - color: '#AA6746', - aceMode: 'text', - tmScope: 'source.solidity', - extensions: ['.sol'], - parsers: ['solidity-parse'], - vscodeLanguageIds: ['solidity'] - } + { + linguistLanguageId: 237469032, + name: 'Solidity', + type: 'programming', + color: '#AA6746', + aceMode: 'text', + tmScope: 'source.solidity', + extensions: ['.sol'], + parsers: ['solidity-parse'], + vscodeLanguageIds: ['solidity'] + } ]; // https://prettier.io/docs/en/plugins.html#parsers const parser = { astFormat: 'solidity-ast', parse, ...loc }; const parsers = { - 'solidity-parse': parser + 'solidity-parse': parser }; const canAttachComment = (node) => - node.type && node.type !== 'BlockComment' && node.type !== 'LineComment'; + node.type && node.type !== 'BlockComment' && node.type !== 'LineComment'; // https://prettier.io/docs/en/plugins.html#printers const printers = { - 'solidity-ast': { - canAttachComment, - handleComments: { - ownLine: handleComments.handleOwnLineComment, - endOfLine: handleComments.handleEndOfLineComment, - remaining: handleComments.handleRemainingComment - }, - isBlockComment: handleComments.isBlockComment, - massageAstNode, - print, - printComment - } + 'solidity-ast': { + canAttachComment, + handleComments: { + ownLine: handleComments.handleOwnLineComment, + endOfLine: handleComments.handleEndOfLineComment, + remaining: handleComments.handleRemainingComment + }, + isBlockComment: handleComments.isBlockComment, + massageAstNode, + print, + printComment + } }; // https://prettier.io/docs/en/plugins.html#defaultoptions const defaultOptions = { - bracketSpacing: false, - tabWidth: 4 + bracketSpacing: false, + tabWidth: 4 }; export default { - languages, - parsers, - printers, - options, - defaultOptions + languages, + parsers, + printers, + options, + defaultOptions }; diff --git a/apps/remix-ide/src/app/plugins/code-format/parser.ts b/apps/remix-ide/src/app/plugins/code-format/parser.ts index 15ef38f871..0fb913fed7 100644 --- a/apps/remix-ide/src/app/plugins/code-format/parser.ts +++ b/apps/remix-ide/src/app/plugins/code-format/parser.ts @@ -80,113 +80,113 @@ export function parse(text, _parsers, options) { }, BinaryOperation(ctx) { switch (ctx.operator) { - case '+': - case '-': - ctx.left = tryHug(ctx.left, ['%']); - ctx.right = tryHug(ctx.right, ['%']); - break; - case '*': - ctx.left = tryHug(ctx.left, ['/', '%']); - break; - case '/': - ctx.left = tryHug(ctx.left, ['*', '%']); - break; - case '%': - ctx.left = tryHug(ctx.left, ['*', '/', '%']); - break; - case '**': - // If the compiler has not been given as an option using we leave a**b**c. - if (!compiler) break; + case '+': + case '-': + ctx.left = tryHug(ctx.left, ['%']); + ctx.right = tryHug(ctx.right, ['%']); + break; + case '*': + ctx.left = tryHug(ctx.left, ['/', '%']); + break; + case '/': + ctx.left = tryHug(ctx.left, ['*', '%']); + break; + case '%': + ctx.left = tryHug(ctx.left, ['*', '/', '%']); + break; + case '**': + // If the compiler has not been given as an option using we leave a**b**c. + if (!compiler) break; - if (semver.satisfies(compiler, '<0.8.0')) { - // If the compiler is less than 0.8.0 then a**b**c is formatted as - // (a**b)**c. - ctx.left = tryHug(ctx.left, ['**']); - break; - } - if ( - ctx.left.type === 'BinaryOperation' && - ctx.left.operator === '**' - ) { - // the parser still organizes the a**b**c as (a**b)**c so we need - // to restructure it. - ctx.right = { - type: 'TupleExpression', - components: [ - { - type: 'BinaryOperation', - operator: '**', - left: ctx.left.right, - right: ctx.right - } - ], - isArray: false - }; - ctx.left = ctx.left.left; - } - break; - case '<<': - case '>>': - ctx.left = tryHug(ctx.left, ['+', '-', '*', '/', '**', '<<', '>>']); - ctx.right = tryHug(ctx.right, ['+', '-', '*', '/', '**']); - break; - case '&': - ctx.left = tryHug(ctx.left, ['+', '-', '*', '/', '**', '<<', '>>']); - ctx.right = tryHug(ctx.right, ['+', '-', '*', '/', '**', '<<', '>>']); - break; - case '|': - ctx.left = tryHug(ctx.left, [ - '+', - '-', - '*', - '/', - '**', - '<<', - '>>', - '&', - '^' - ]); - ctx.right = tryHug(ctx.right, [ - '+', - '-', - '*', - '/', - '**', - '<<', - '>>', - '&', - '^' - ]); - break; - case '^': - ctx.left = tryHug(ctx.left, [ - '+', - '-', - '*', - '/', - '**', - '<<', - '>>', - '&' - ]); - ctx.right = tryHug(ctx.right, [ - '+', - '-', - '*', - '/', - '**', - '<<', - '>>', - '&' - ]); - break; - case '||': - ctx.left = tryHug(ctx.left, ['&&']); - ctx.right = tryHug(ctx.right, ['&&']); - break; - case '&&': - default: + if (semver.satisfies(compiler, '<0.8.0')) { + // If the compiler is less than 0.8.0 then a**b**c is formatted as + // (a**b)**c. + ctx.left = tryHug(ctx.left, ['**']); break; + } + if ( + ctx.left.type === 'BinaryOperation' && + ctx.left.operator === '**' + ) { + // the parser still organizes the a**b**c as (a**b)**c so we need + // to restructure it. + ctx.right = { + type: 'TupleExpression', + components: [ + { + type: 'BinaryOperation', + operator: '**', + left: ctx.left.right, + right: ctx.right + } + ], + isArray: false + }; + ctx.left = ctx.left.left; + } + break; + case '<<': + case '>>': + ctx.left = tryHug(ctx.left, ['+', '-', '*', '/', '**', '<<', '>>']); + ctx.right = tryHug(ctx.right, ['+', '-', '*', '/', '**']); + break; + case '&': + ctx.left = tryHug(ctx.left, ['+', '-', '*', '/', '**', '<<', '>>']); + ctx.right = tryHug(ctx.right, ['+', '-', '*', '/', '**', '<<', '>>']); + break; + case '|': + ctx.left = tryHug(ctx.left, [ + '+', + '-', + '*', + '/', + '**', + '<<', + '>>', + '&', + '^' + ]); + ctx.right = tryHug(ctx.right, [ + '+', + '-', + '*', + '/', + '**', + '<<', + '>>', + '&', + '^' + ]); + break; + case '^': + ctx.left = tryHug(ctx.left, [ + '+', + '-', + '*', + '/', + '**', + '<<', + '>>', + '&' + ]); + ctx.right = tryHug(ctx.right, [ + '+', + '-', + '*', + '/', + '**', + '<<', + '>>', + '&' + ]); + break; + case '||': + ctx.left = tryHug(ctx.left, ['&&']); + ctx.right = tryHug(ctx.right, ['&&']); + break; + case '&&': + default: + break; } } }); diff --git a/apps/remix-ide/src/app/plugins/contractFlattener.tsx b/apps/remix-ide/src/app/plugins/contractFlattener.tsx index b61915372d..2c3640bcd9 100644 --- a/apps/remix-ide/src/app/plugins/contractFlattener.tsx +++ b/apps/remix-ide/src/app/plugins/contractFlattener.tsx @@ -1,9 +1,9 @@ import React from 'react' -import { Plugin } from '@remixproject/engine' -import { customAction } from '@remixproject/plugin-api' -import { concatSourceFiles, getDependencyGraph, normalizeContractPath } from '@remix-ui/solidity-compiler' +import {Plugin} from '@remixproject/engine' +import {customAction} from '@remixproject/plugin-api' +import {concatSourceFiles, getDependencyGraph, normalizeContractPath} from '@remix-ui/solidity-compiler' -const _paq = window._paq = window._paq || [] +const _paq = (window._paq = window._paq || []) const profile = { name: 'contractflattener', @@ -11,11 +11,10 @@ const profile = { description: 'Flatten solidity contracts', methods: ['flattenAContract', 'flattenContract'], events: [], - maintainedBy: 'Remix', + maintainedBy: 'Remix' } export class ContractFlattener extends Plugin { - triggerFlattenContract: boolean = false constructor() { super(profile) @@ -23,13 +22,13 @@ export class ContractFlattener extends Plugin { onActivation(): void { this.on('solidity', 'compilationFinished', async (file, source, languageVersion, data, input, version) => { - if(data.sources && Object.keys(data.sources).length > 1) { - if(this.triggerFlattenContract) { + if (data.sources && Object.keys(data.sources).length > 1) { + if (this.triggerFlattenContract) { this.triggerFlattenContract = false await this.flattenContract(source, file, data) } } - }) + }) _paq.push(['trackEvent', 'plugin', 'activated', 'contractFlattener']) } @@ -48,8 +47,7 @@ export class ContractFlattener extends Plugin { * Takes the flattened result, writes it to a file and returns the result. * @returns {Promise} */ - async flattenContract (source: { sources: any, target: string }, - filePath: string, data: { contracts: any, sources: any }): Promise { + async flattenContract(source: {sources: any; target: string}, filePath: string, data: {contracts: any; sources: any}): Promise { const appendage = '_flattened.sol' const normalized = normalizeContractPath(filePath) const path = `${normalized[normalized.length - 2]}${appendage}` @@ -58,17 +56,15 @@ export class ContractFlattener extends Plugin { let sorted let result let sources - try{ + try { dependencyGraph = getDependencyGraph(ast, filePath) - sorted = dependencyGraph.isEmpty() - ? [filePath] - : dependencyGraph.sort().reverse() + sorted = dependencyGraph.isEmpty() ? [filePath] : dependencyGraph.sort().reverse() sources = source.sources result = concatSourceFiles(sorted, sources) - }catch(err){ + } catch (err) { console.warn(err) } - await this.call('fileManager', 'writeFile', path , result) + await this.call('fileManager', 'writeFile', path, result) _paq.push(['trackEvent', 'plugin', 'contractFlattener', 'flattenAContract']) // clean up memory references & return result sorted = null @@ -76,4 +72,4 @@ export class ContractFlattener extends Plugin { dependencyGraph = null return result } -} \ No newline at end of file +} diff --git a/apps/remix-ide/src/app/plugins/file-decorator.ts b/apps/remix-ide/src/app/plugins/file-decorator.ts index 31aaf109be..34829b027b 100644 --- a/apps/remix-ide/src/app/plugins/file-decorator.ts +++ b/apps/remix-ide/src/app/plugins/file-decorator.ts @@ -6,79 +6,79 @@ import { Plugin } from '@remixproject/engine' import { fileDecoration } from '@remix-ui/file-decorators' const profile = { - name: 'fileDecorator', - desciption: 'Keeps decorators of the files', - methods: ['setFileDecorators', 'clearFileDecorators', 'clearAllFileDecorators'], - events: ['fileDecoratorsChanged'], - version: '0.0.1' + name: 'fileDecorator', + desciption: 'Keeps decorators of the files', + methods: ['setFileDecorators', 'clearFileDecorators', 'clearAllFileDecorators'], + events: ['fileDecoratorsChanged'], + version: '0.0.1' } export class FileDecorator extends Plugin { - private _fileStates: fileDecoration[] = [] - constructor() { - super(profile) - } + private _fileStates: fileDecoration[] = [] + constructor() { + super(profile) + } - onActivation(): void { - this.on('filePanel', 'setWorkspace', async () => { - await this.clearAllFileDecorators() - }) - } + onActivation(): void { + this.on('filePanel', 'setWorkspace', async () => { + await this.clearAllFileDecorators() + }) + } - /** + /** * @param fileStates Array of file states */ - async setFileDecorators(fileStates: fileDecoration[] | fileDecoration) { - const { from } = this.currentRequest - const workspace = await this.call('filePanel', 'getCurrentWorkspace') - const fileStatesPayload = Array.isArray(fileStates) ? fileStates : [fileStates] - // clear all file states in the previous state of this owner on the files called - fileStatesPayload.forEach((state) => { - state.workspace = workspace - state.owner = from - }) - const filteredState = this._fileStates.filter((state) => { - const index = fileStatesPayload.findIndex((payloadFileState: fileDecoration) => { - return from == state.owner && payloadFileState.path == state.path - }) - return index == -1 - }) - const newState = [...filteredState, ...fileStatesPayload].sort(sortByPath) + async setFileDecorators(fileStates: fileDecoration[] | fileDecoration) { + const { from } = this.currentRequest + const workspace = await this.call('filePanel', 'getCurrentWorkspace') + const fileStatesPayload = Array.isArray(fileStates) ? fileStates : [fileStates] + // clear all file states in the previous state of this owner on the files called + fileStatesPayload.forEach((state) => { + state.workspace = workspace + state.owner = from + }) + const filteredState = this._fileStates.filter((state) => { + const index = fileStatesPayload.findIndex((payloadFileState: fileDecoration) => { + return from == state.owner && payloadFileState.path == state.path + }) + return index == -1 + }) + const newState = [...filteredState, ...fileStatesPayload].sort(sortByPath) - if (!deepequal(newState, this._fileStates)) { - this._fileStates = newState - this.emit('fileDecoratorsChanged', this._fileStates) - } + if (!deepequal(newState, this._fileStates)) { + this._fileStates = newState + this.emit('fileDecoratorsChanged', this._fileStates) } + } - async clearFileDecorators(path?: string) { - const { from } = this.currentRequest - if (!from) return + async clearFileDecorators(path?: string) { + const { from } = this.currentRequest + if (!from) return - const filteredState = this._fileStates.filter((state) => { - if(state.owner != from) return true - if(path && state.path != path) return true - }) - const newState = [...filteredState].sort(sortByPath) - - if (!deepequal(newState, this._fileStates)) { - this._fileStates = newState - this.emit('fileDecoratorsChanged', this._fileStates) - } + const filteredState = this._fileStates.filter((state) => { + if(state.owner != from) return true + if(path && state.path != path) return true + }) + const newState = [...filteredState].sort(sortByPath) + if (!deepequal(newState, this._fileStates)) { + this._fileStates = newState + this.emit('fileDecoratorsChanged', this._fileStates) } - async clearAllFileDecorators() { - this._fileStates = [] - this.emit('fileDecoratorsChanged', []) - } + } + + async clearAllFileDecorators() { + this._fileStates = [] + this.emit('fileDecoratorsChanged', []) + } } const sortByPath = (a: fileDecoration, b: fileDecoration) => { - if (a.path < b.path) { - return -1; - } - if (a.path > b.path) { - return 1; - } - return 0; + if (a.path < b.path) { + return -1; + } + if (a.path > b.path) { + return 1; + } + return 0; } \ No newline at end of file diff --git a/apps/remix-ide/src/app/plugins/notification.tsx b/apps/remix-ide/src/app/plugins/notification.tsx index 83754e8b38..ca2b27437a 100644 --- a/apps/remix-ide/src/app/plugins/notification.tsx +++ b/apps/remix-ide/src/app/plugins/notification.tsx @@ -1,11 +1,11 @@ -import { Plugin } from '@remixproject/engine' -import { LibraryProfile, MethodApi, StatusEvents } from '@remixproject/plugin-utils' -import { AppModal } from '@remix-ui/app' -import { AlertModal } from '@remix-ui/app' -import { dispatchModalInterface } from '@remix-ui/app' +import {Plugin} from '@remixproject/engine' +import {LibraryProfile, MethodApi, StatusEvents} from '@remixproject/plugin-utils' +import {AppModal} from '@remix-ui/app' +import {AlertModal} from '@remix-ui/app' +import {dispatchModalInterface} from '@remix-ui/app' interface INotificationApi { - events: StatusEvents, + events: StatusEvents methods: { modal: (args: AppModal) => void alert: (args: AlertModal) => void @@ -13,7 +13,7 @@ interface INotificationApi { } } -const profile:LibraryProfile = { +const profile: LibraryProfile = { name: 'notification', displayName: 'Notification', description: 'Displays notifications', @@ -22,23 +22,23 @@ const profile:LibraryProfile = { export class NotificationPlugin extends Plugin implements MethodApi { dispatcher: dispatchModalInterface - constructor () { + constructor() { super(profile) } - setDispatcher (dispatcher: dispatchModalInterface) { + setDispatcher(dispatcher: dispatchModalInterface) { this.dispatcher = dispatcher } - async modal (args: AppModal) { + async modal(args: AppModal) { return this.dispatcher.modal(args) } - async alert (args: AlertModal) { + async alert(args: AlertModal) { return this.dispatcher.alert(args) } - async toast (message: string | JSX.Element) { + async toast(message: string | JSX.Element) { this.dispatcher.toast(message) } } diff --git a/apps/remix-ide/src/app/plugins/openaigpt.tsx b/apps/remix-ide/src/app/plugins/openaigpt.tsx new file mode 100644 index 0000000000..e95babe00a --- /dev/null +++ b/apps/remix-ide/src/app/plugins/openaigpt.tsx @@ -0,0 +1,47 @@ +import { Plugin } from '@remixproject/engine' +import { CreateChatCompletionResponse } from 'openai' + +const _paq = (window._paq = window._paq || []) + +const profile = { + name: 'openaigpt', + displayName: 'openaigpt', + description: 'openaigpt', + methods: ['message'], + events: [], + maintainedBy: 'Remix', +} + +export class OpenAIGpt extends Plugin { + constructor() { + super(profile) + } + + async message(prompt): Promise { + this.call('layout', 'maximizeTerminal') + this.call('terminal', 'log', 'Waiting for GPT answer...') + let result + try { + result = await ( + await fetch('https://openai-gpt.remixproject.org', { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ prompt }), + }) + ).json() + } catch (e) { + this.call('terminal', 'log', { type: 'typewritererror', value: `Unable to get a response ${e.message}` }) + return + } + + if (result && result.choices && result.choices.length) { + this.call('terminal', 'log', { type: 'typewritersuccess', value: result.choices[0].message.content }) + } else { + this.call('terminal', 'log', { type: 'typewritersuccess', value: 'No response...' }) + } + return result.data + } +} diff --git a/apps/remix-ide/src/app/plugins/parser/code-parser.tsx b/apps/remix-ide/src/app/plugins/parser/code-parser.tsx index cd0445f1b2..c95cb9efca 100644 --- a/apps/remix-ide/src/app/plugins/parser/code-parser.tsx +++ b/apps/remix-ide/src/app/plugins/parser/code-parser.tsx @@ -1,698 +1,764 @@ 'use strict' -import { Plugin } from '@remixproject/engine' -import { sourceMappingDecoder } from '@remix-project/remix-debug' -import { CompilerAbstract } from '@remix-project/remix-solidity' -import { CompilationResult } from '@remix-project/remix-solidity' +import {Plugin} from '@remixproject/engine' +import {sourceMappingDecoder} from '@remix-project/remix-debug' +import {CompilerAbstract} from '@remix-project/remix-solidity' +import {CompilationResult} from '@remix-project/remix-solidity' import CodeParserGasService from './services/code-parser-gas-service' import CodeParserCompiler from './services/code-parser-compiler' import CodeParserAntlrService from './services/code-parser-antlr-service' -import CodeParserImports, { CodeParserImportsData } from './services/code-parser-imports' +import CodeParserImports, {CodeParserImportsData} from './services/code-parser-imports' import React from 'react' -import { Profile } from '@remixproject/plugin-utils' -import { ContractDefinitionAstNode, EventDefinitionAstNode, FunctionCallAstNode, FunctionDefinitionAstNode, IdentifierAstNode, ImportDirectiveAstNode, ModifierDefinitionAstNode, SourceUnitAstNode, StructDefinitionAstNode, VariableDeclarationAstNode } from '@remix-project/remix-analyzer' -import { lastCompilationResult, RemixApi } from '@remixproject/plugin-api' -import { antlr } from './types' -import { ParseResult } from './types/antlr-types' +import {Profile} from '@remixproject/plugin-utils' +import { + ContractDefinitionAstNode, + EventDefinitionAstNode, + FunctionCallAstNode, + FunctionDefinitionAstNode, + IdentifierAstNode, + ImportDirectiveAstNode, + ModifierDefinitionAstNode, + SourceUnitAstNode, + StructDefinitionAstNode, + VariableDeclarationAstNode +} from '@remix-project/remix-analyzer' +import {lastCompilationResult, RemixApi} from '@remixproject/plugin-api' +import {antlr} from './types' +import {ParseResult} from './types/antlr-types' const profile: Profile = { - name: 'codeParser', - methods: ['nodesAtPosition', 'getContractNodes', 'getCurrentFileNodes', 'getLineColumnOfNode', 'getLineColumnOfPosition', 'getFunctionParamaters', 'getDeclaration', 'getFunctionReturnParameters', 'getVariableDeclaration', 'getNodeDocumentation', 'getNodeLink', 'listAstNodes', 'getANTLRBlockAtPosition', 'getLastNodeInLine', 'resolveImports', 'parseSolidity', 'getNodesWithScope', 'getNodesWithName', 'getNodes', 'compile', 'getNodeById', 'getLastCompilationResult', 'positionOfDefinition', 'definitionAtPosition', 'jumpToDefinition', 'referrencesAtPosition', 'referencesOf', 'getActiveHighlights', 'gasEstimation', 'declarationOf', 'getGasEstimates', 'getImports'], - events: [], - version: '0.0.1' + name: 'codeParser', + methods: [ + 'nodesAtPosition', + 'getContractNodes', + 'getCurrentFileNodes', + 'getLineColumnOfNode', + 'getLineColumnOfPosition', + 'getFunctionParamaters', + 'getDeclaration', + 'getFunctionReturnParameters', + 'getVariableDeclaration', + 'getNodeDocumentation', + 'getNodeLink', + 'listAstNodes', + 'getANTLRBlockAtPosition', + 'getLastNodeInLine', + 'resolveImports', + 'parseSolidity', + 'getNodesWithScope', + 'getNodesWithName', + 'getNodes', + 'compile', + 'getNodeById', + 'getLastCompilationResult', + 'positionOfDefinition', + 'definitionAtPosition', + 'jumpToDefinition', + 'referrencesAtPosition', + 'referencesOf', + 'getActiveHighlights', + 'gasEstimation', + 'declarationOf', + 'getGasEstimates', + 'getImports' + ], + events: [], + version: '0.0.1' } export function isNodeDefinition(node: genericASTNode) { - return node.nodeType === 'ContractDefinition' || - node.nodeType === 'FunctionDefinition' || - node.nodeType === 'ModifierDefinition' || - node.nodeType === 'VariableDeclaration' || - node.nodeType === 'StructDefinition' || - node.nodeType === 'EventDefinition' + return ( + node.nodeType === 'ContractDefinition' || + node.nodeType === 'FunctionDefinition' || + node.nodeType === 'ModifierDefinition' || + node.nodeType === 'VariableDeclaration' || + node.nodeType === 'StructDefinition' || + node.nodeType === 'EventDefinition' + ) } export type genericASTNode = - ContractDefinitionAstNode - | FunctionDefinitionAstNode - | ModifierDefinitionAstNode - | VariableDeclarationAstNode - | StructDefinitionAstNode - | EventDefinitionAstNode - | IdentifierAstNode - | FunctionCallAstNode - | ImportDirectiveAstNode - | SourceUnitAstNode + | ContractDefinitionAstNode + | FunctionDefinitionAstNode + | ModifierDefinitionAstNode + | VariableDeclarationAstNode + | StructDefinitionAstNode + | EventDefinitionAstNode + | IdentifierAstNode + | FunctionCallAstNode + | ImportDirectiveAstNode + | SourceUnitAstNode interface flatReferenceIndexNode { - [id: number]: genericASTNode + [id: number]: genericASTNode } interface declarationIndexNode { - [id: number]: genericASTNode[] + [id: number]: genericASTNode[] } interface codeParserIndex { - declarations: declarationIndexNode, - flatReferences: flatReferenceIndexNode, - nodesPerFile: any + declarations: declarationIndexNode + flatReferences: flatReferenceIndexNode + nodesPerFile: any } export class CodeParser extends Plugin { - - compilerAbstract: CompilerAbstract - currentFile: string - nodeIndex: codeParserIndex - astWalker: any - errorState: boolean = false - - gastEstimateTimeOut: any - - gasService: CodeParserGasService - compilerService: CodeParserCompiler - antlrService: CodeParserAntlrService - importService: CodeParserImports - - parseSolidity: (text: string) => Promise - getLastNodeInLine: (ast: string) => Promise - listAstNodes: () => Promise - getANTLRBlockAtPosition: (position: any, text?: string) => Promise - setCurrentFileAST: (text?: string) => Promise - getImports: () => Promise - - debuggerIsOn: boolean = false - - - constructor(astWalker: any) { - super(profile) - this.astWalker = astWalker - this.nodeIndex = { - declarations: [[]], - flatReferences: [], - nodesPerFile: {} + compilerAbstract: CompilerAbstract + currentFile: string + nodeIndex: codeParserIndex + astWalker: any + errorState: boolean = false + + gastEstimateTimeOut: any + + gasService: CodeParserGasService + compilerService: CodeParserCompiler + antlrService: CodeParserAntlrService + importService: CodeParserImports + + parseSolidity: (text: string) => Promise + getLastNodeInLine: (ast: string) => Promise + listAstNodes: () => Promise + getANTLRBlockAtPosition: (position: any, text?: string) => Promise + setCurrentFileAST: (text?: string) => Promise + getImports: () => Promise + + debuggerIsOn: boolean = false + + constructor(astWalker: any) { + super(profile) + this.astWalker = astWalker + this.nodeIndex = { + declarations: [[]], + flatReferences: [], + nodesPerFile: {} + } + } + + async handleChangeEvents() { + const completionSettings = await this.call('config', 'getAppParameter', 'auto-completion') + if (completionSettings) { + this.antlrService.enableWorker() + } else { + this.antlrService.disableWorker() + } + const showGasSettings = await this.call('config', 'getAppParameter', 'show-gas') + const showErrorSettings = await this.call('config', 'getAppParameter', 'display-errors') + if (showGasSettings || showErrorSettings || completionSettings || this.debuggerIsOn) { + await this.compilerService.compile() + } + } + + async onActivation() { + this.gasService = new CodeParserGasService(this) + this.compilerService = new CodeParserCompiler(this) + this.antlrService = new CodeParserAntlrService(this) + this.importService = new CodeParserImports(this) + + this.parseSolidity = this.antlrService.parseSolidity.bind(this.antlrService) + this.getLastNodeInLine = this.antlrService.getLastNodeInLine.bind(this.antlrService) + this.listAstNodes = this.antlrService.listAstNodes.bind(this.antlrService) + this.getANTLRBlockAtPosition = this.antlrService.getANTLRBlockAtPosition.bind(this.antlrService) + this.setCurrentFileAST = this.antlrService.setCurrentFileAST.bind(this.antlrService) + this.getImports = this.importService.getImports.bind(this.importService) + + this.on('editor', 'didChangeFile', async (file) => { + await this.call('editor', 'discardLineTexts') + await this.handleChangeEvents() + }) + + this.on('filePanel', 'setWorkspace', async () => { + await this.call('fileDecorator', 'clearFileDecorators') + await this.importService.setFileTree() + }) + + this.on('fileManager', 'fileAdded', async () => { + await this.importService.setFileTree() + }) + this.on('fileManager', 'fileRemoved', async () => { + await this.importService.setFileTree() + }) + + this.on('fileManager', 'currentFileChanged', async () => { + await this.call('editor', 'discardLineTexts') + const completionSettings = await this.call('config', 'getAppParameter', 'auto-completion') + if (completionSettings) { + this.antlrService.setCurrentFileAST() + } + await this.handleChangeEvents() + }) + + this.on('solidity', 'loadingCompiler', async (url) => { + this.compilerService.compiler.loadVersion(true, `${url}?t=${Date.now()}`) + }) + + this.on('config', 'configChanged', async (config) => { + await this.reload() + }) + + this.on('settings', 'configChanged', async (config) => { + await this.reload() + }) + + await this.compilerService.init() + this.on('solidity', 'compilerLoaded', async () => { + await this.reload() + }) + + this.on('debugger', 'startDebugging', async () => { + this.debuggerIsOn = true + await this.reload() + }) + + this.on('debugger', 'stopDebugging', async () => { + this.debuggerIsOn = false + await this.reload() + }) + } + + async reload() { + await this.call('editor', 'discardLineTexts') + await this.call('fileDecorator', 'clearFileDecorators') + await this.call('editor', 'clearErrorMarkers', [this.currentFile]) + await this.handleChangeEvents() + } + + /** + * + * @returns + */ + async getLastCompilationResult() { + return this.compilerAbstract + } + + getSubNodes(node: T): number[] { + return node.nodeType == 'ContractDefinition' && node.contractDependencies + } + + /** + * Builds a flat index and declarations of all the nodes in the compilation result + * @param compilationResult + * @param source + */ + _buildIndex(compilationResult: CompilationResult, source) { + if (compilationResult && compilationResult.sources) { + const callback = (node: genericASTNode) => { + if (node && 'referencedDeclaration' in node && node.referencedDeclaration) { + if (!this.nodeIndex.declarations[node.referencedDeclaration]) { + this.nodeIndex.declarations[node.referencedDeclaration] = [] + } + this.nodeIndex.declarations[node.referencedDeclaration].push(node) } - } - - async handleChangeEvents() { - const completionSettings = await this.call('config', 'getAppParameter', 'auto-completion') - if (completionSettings) { - this.antlrService.enableWorker() - } else { - this.antlrService.disableWorker() - } - const showGasSettings = await this.call('config', 'getAppParameter', 'show-gas') - const showErrorSettings = await this.call('config', 'getAppParameter', 'display-errors') - if (showGasSettings || showErrorSettings || completionSettings || this.debuggerIsOn) { - await this.compilerService.compile() + this.nodeIndex.flatReferences[node.id] = node + } + for (const s in compilationResult.sources) { + this.astWalker.walkFull(compilationResult.sources[s].ast, callback) + } + } + } + + // NODE HELPERS + + _getInputParams(node: FunctionDefinitionAstNode) { + const params = [] + const target = node.parameters + if (target) { + const children = target.parameters + for (const j in children) { + if (children[j].nodeType === 'VariableDeclaration') { + params.push(children[j].typeDescriptions.typeString) } - } - - async onActivation() { - - this.gasService = new CodeParserGasService(this) - this.compilerService = new CodeParserCompiler(this) - this.antlrService = new CodeParserAntlrService(this) - this.importService = new CodeParserImports(this) - - this.parseSolidity = this.antlrService.parseSolidity.bind(this.antlrService) - this.getLastNodeInLine = this.antlrService.getLastNodeInLine.bind(this.antlrService) - this.listAstNodes = this.antlrService.listAstNodes.bind(this.antlrService) - this.getANTLRBlockAtPosition = this.antlrService.getANTLRBlockAtPosition.bind(this.antlrService) - this.setCurrentFileAST = this.antlrService.setCurrentFileAST.bind(this.antlrService) - this.getImports = this.importService.getImports.bind(this.importService) - - this.on('editor', 'didChangeFile', async (file) => { - await this.call('editor', 'discardLineTexts') - await this.handleChangeEvents() - }) - - this.on('filePanel', 'setWorkspace', async () => { - await this.call('fileDecorator', 'clearFileDecorators') - await this.importService.setFileTree() - }) - - this.on('fileManager', 'fileAdded', async () => { - await this.importService.setFileTree() - }) - this.on('fileManager', 'fileRemoved', async () => { - await this.importService.setFileTree() - }) - - this.on('fileManager', 'currentFileChanged', async () => { - await this.call('editor', 'discardLineTexts') - const completionSettings = await this.call('config', 'getAppParameter', 'auto-completion') - if (completionSettings) { - this.antlrService.setCurrentFileAST() - } - await this.handleChangeEvents() - }) - - this.on('solidity', 'loadingCompiler', async (url) => { - this.compilerService.compiler.loadVersion(true, `${url}?t=${Date.now()}`) - }) - - this.on('config', 'configChanged', async (config) => { - await this.reload() - }) - - this.on('settings', 'configChanged', async (config) => { - await this.reload() - }) - - await this.compilerService.init() - this.on('solidity', 'compilerLoaded', async () => { - await this.reload() - }) - - this.on('debugger', 'startDebugging', async () => { - this.debuggerIsOn = true - await this.reload() - }) - - this.on('debugger', 'stopDebugging', async () => { - this.debuggerIsOn = false - await this.reload() - }) - } - - async reload(){ - await this.call('editor', 'discardLineTexts') - await this.call('fileDecorator', 'clearFileDecorators') - await this.call('editor', 'clearErrorMarkers', [this.currentFile]) - await this.handleChangeEvents() - } - - /** - * - * @returns - */ - async getLastCompilationResult() { - return this.compilerAbstract - } - - getSubNodes(node: T): number[] { - return node.nodeType == "ContractDefinition" && node.contractDependencies; - } - - /** - * Builds a flat index and declarations of all the nodes in the compilation result - * @param compilationResult - * @param source - */ - _buildIndex(compilationResult: CompilationResult, source) { - if (compilationResult && compilationResult.sources) { - const callback = (node: genericASTNode) => { - if (node && ("referencedDeclaration" in node) && node.referencedDeclaration) { - if (!this.nodeIndex.declarations[node.referencedDeclaration]) { - this.nodeIndex.declarations[node.referencedDeclaration] = [] + } + } + return '(' + params.toString() + ')' + } + + _flatNodeList(contractNode: ContractDefinitionAstNode, fileName: string, inScope: boolean, compilatioResult: any) { + const index = {} + const contractName: string = contractNode.name + const callback = (node) => { + if (inScope && node.scope !== contractNode.id && !(node.nodeType === 'EnumDefinition' || node.nodeType === 'EventDefinition' || node.nodeType === 'ModifierDefinition')) + return + if (inScope) node.isClassNode = true + node.gasEstimate = this._getContractGasEstimate(node, contractName, fileName, compilatioResult) + node.functionName = node.name + this._getInputParams(node) + node.contractName = contractName + node.contractId = contractNode.id + index[node.id] = node + } + this.astWalker.walkFull(contractNode, callback) + return index + } + + _extractFileNodes(fileName: string, compilationResult: lastCompilationResult) { + if (compilationResult && compilationResult.data.sources && compilationResult.data.sources[fileName]) { + const source = compilationResult.data.sources[fileName] + const nodesByContract: any = {} + nodesByContract.imports = {} + nodesByContract.contracts = {} + this.astWalker.walkFull(source.ast, async (node) => { + if (node.nodeType === 'ContractDefinition') { + const flatNodes = this._flatNodeList(node, fileName, false, compilationResult) + node.gasEstimate = this._getContractGasEstimate(node, node.name, fileName, compilationResult) + nodesByContract.contracts[node.name] = { + contractDefinition: node, + contractNodes: flatNodes + } + const baseNodes = {} + const baseNodesWithBaseContractScope = {} + if (node.linearizedBaseContracts) { + for (const id of node.linearizedBaseContracts) { + if (id !== node.id) { + const baseContract = await this.getNodeById(id) + const callback = (node) => { + node.contractName = (baseContract as any).name + node.contractId = (baseContract as any).id + node.isBaseNode = true + baseNodes[node.id] = node + if ((node.scope && node.scope === baseContract.id) || node.nodeType === 'EnumDefinition' || node.nodeType === 'EventDefinition') { + baseNodesWithBaseContractScope[node.id] = node + } + if (node.members) { + for (const member of node.members) { + member.contractName = (baseContract as any).name + member.contractId = (baseContract as any).id + member.isBaseNode = true } - this.nodeIndex.declarations[node.referencedDeclaration].push(node) - } - this.nodeIndex.flatReferences[node.id] = node - } - for (const s in compilationResult.sources) { - this.astWalker.walkFull(compilationResult.sources[s].ast, callback) - } - - } - - } - - // NODE HELPERS - - _getInputParams(node: FunctionDefinitionAstNode) { - const params = [] - const target = node.parameters - if (target) { - const children = target.parameters - for (const j in children) { - if (children[j].nodeType === 'VariableDeclaration') { - params.push(children[j].typeDescriptions.typeString) + } } + this.astWalker.walkFull(baseContract, callback) + } } + } + nodesByContract.contracts[node.name].baseNodes = baseNodes + nodesByContract.contracts[node.name].baseNodesWithBaseContractScope = baseNodesWithBaseContractScope + nodesByContract.contracts[node.name].contractScopeNodes = this._flatNodeList(node, fileName, true, compilationResult) } - return '(' + params.toString() + ')' - } - - - _flatNodeList(contractNode: ContractDefinitionAstNode, fileName: string, inScope: boolean, compilatioResult: any) { - const index = {} - const contractName: string = contractNode.name - const callback = (node) => { - if (inScope && node.scope !== contractNode.id - && !(node.nodeType === 'EnumDefinition' || node.nodeType === 'EventDefinition' || node.nodeType === 'ModifierDefinition')) - return - if (inScope) node.isClassNode = true; - node.gasEstimate = this._getContractGasEstimate(node, contractName, fileName, compilatioResult) - node.functionName = node.name + this._getInputParams(node) - node.contractName = contractName - node.contractId = contractNode.id - index[node.id] = node + if (node.nodeType === 'ImportDirective') { + const imported = await this.resolveImports(node, {}) + + for (const importedNode of Object.values(imported) as any) { + if (importedNode.nodes) + for (const subNode of importedNode.nodes) { + nodesByContract.imports[subNode.id] = subNode + } + } } - this.astWalker.walkFull(contractNode, callback) - return index - } - - _extractFileNodes(fileName: string, compilationResult: lastCompilationResult) { - if (compilationResult && compilationResult.data.sources && compilationResult.data.sources[fileName]) { - const source = compilationResult.data.sources[fileName] - const nodesByContract: any = {} - nodesByContract.imports = {} - nodesByContract.contracts = {} - this.astWalker.walkFull(source.ast, async (node) => { - if (node.nodeType === 'ContractDefinition') { - const flatNodes = this._flatNodeList(node, fileName, false, compilationResult) - node.gasEstimate = this._getContractGasEstimate(node, node.name, fileName, compilationResult) - nodesByContract.contracts[node.name] = { contractDefinition: node, contractNodes: flatNodes } - const baseNodes = {} - const baseNodesWithBaseContractScope = {} - if (node.linearizedBaseContracts) { - for (const id of node.linearizedBaseContracts) { - if (id !== node.id) { - const baseContract = await this.getNodeById(id) - const callback = (node) => { - node.contractName = (baseContract as any).name - node.contractId = (baseContract as any).id - node.isBaseNode = true; - baseNodes[node.id] = node - if ((node.scope && node.scope === baseContract.id) - || node.nodeType === 'EnumDefinition' - || node.nodeType === 'EventDefinition' - ) { - baseNodesWithBaseContractScope[node.id] = node - } - if (node.members) { - for (const member of node.members) { - member.contractName = (baseContract as any).name - member.contractId = (baseContract as any).id - member.isBaseNode = true; - } - } - } - this.astWalker.walkFull(baseContract, callback) - } - } - } - nodesByContract.contracts[node.name].baseNodes = baseNodes - nodesByContract.contracts[node.name].baseNodesWithBaseContractScope = baseNodesWithBaseContractScope - nodesByContract.contracts[node.name].contractScopeNodes = this._flatNodeList(node, fileName, true, compilationResult) - } - if (node.nodeType === 'ImportDirective') { - - const imported = await this.resolveImports(node, {}) - - for (const importedNode of (Object.values(imported) as any)) { - if (importedNode.nodes) - for (const subNode of importedNode.nodes) { - nodesByContract.imports[subNode.id] = subNode - } - } - } - }) - return nodesByContract - } - } - - _getContractGasEstimate(node: ContractDefinitionAstNode | FunctionDefinitionAstNode, contractName: string, fileName: string, compilationResult: lastCompilationResult) { - - const contracts = compilationResult.data.contracts && compilationResult.data.contracts[this.currentFile] - for (const name in contracts) { - if (name === contractName) { - const contract = contracts[name] - const estimationObj = contract.evm && contract.evm.gasEstimates - - let executionCost = null - if (node.nodeType === 'FunctionDefinition') { - const visibility = node.visibility - if (node.kind !== 'constructor') { - const fnName = node.name - const fn = fnName + this._getInputParams(node) - - if (visibility === 'public' || visibility === 'external') { - executionCost = estimationObj === null ? '-' : estimationObj.external[fn] - } else if (visibility === 'private' || visibility === 'internal') { - executionCost = estimationObj === null ? '-' : estimationObj.internal[fn] - } - return { executionCost } - } else { - return { - creationCost: estimationObj === null ? '-' : estimationObj.creation.totalCost, - codeDepositCost: estimationObj === null ? '-' : estimationObj.creation.codeDepositCost, - } - } - } + }) + return nodesByContract + } + } + + _getContractGasEstimate(node: ContractDefinitionAstNode | FunctionDefinitionAstNode, contractName: string, fileName: string, compilationResult: lastCompilationResult) { + const contracts = compilationResult.data.contracts && compilationResult.data.contracts[this.currentFile] + for (const name in contracts) { + if (name === contractName) { + const contract = contracts[name] + const estimationObj = contract.evm && contract.evm.gasEstimates + + let executionCost = null + if (node.nodeType === 'FunctionDefinition') { + const visibility = node.visibility + if (node.kind !== 'constructor') { + const fnName = node.name + const fn = fnName + this._getInputParams(node) + + if (visibility === 'public' || visibility === 'external') { + executionCost = estimationObj === null ? '-' : estimationObj.external[fn] + } else if (visibility === 'private' || visibility === 'internal') { + executionCost = estimationObj === null ? '-' : estimationObj.internal[fn] } - } - } - - /** - * Nodes at position where position is a number, offset - * @param position - * @param type - * @returns - */ - async nodesAtPosition(position: number, type = ''): Promise { - let lastCompilationResult = this.compilerAbstract - if(this.debuggerIsOn) { - lastCompilationResult = await this.call('compilerArtefacts', 'get', '__last') - this.currentFile = await this.call('fileManager', 'file') - } - if (!lastCompilationResult) return [] - const urlFromPath = await this.call('fileManager', 'getUrlFromPath', this.currentFile) - if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data && lastCompilationResult.data.sources && lastCompilationResult.data.sources[this.currentFile]) { - const nodes: genericASTNode[] = sourceMappingDecoder.nodesAtPosition(type, position, lastCompilationResult.data.sources[this.currentFile] || lastCompilationResult.data.sources[urlFromPath.file]) - return nodes - } - return [] - } - - /** - * - * @param id - * @returns - */ - async getNodeById(id: number) { - for (const key in this.nodeIndex.flatReferences) { - if (this.nodeIndex.flatReferences[key].id === id) { - return this.nodeIndex.flatReferences[key] + return {executionCost} + } else { + return { + creationCost: estimationObj === null ? '-' : estimationObj.creation.totalCost, + codeDepositCost: estimationObj === null ? '-' : estimationObj.creation.codeDepositCost } + } } - } - - /** - * - * @param id - * @returns - */ - async getDeclaration(id: number) { - if (this.nodeIndex.declarations && this.nodeIndex.declarations[id]) return this.nodeIndex.declarations[id] - } - - /** - * - * @param scope - * @returns - */ - async getNodesWithScope(scope: number) { - const nodes = [] - for (const node of Object.values(this.nodeIndex.flatReferences)) { - if (node.scope === scope) nodes.push(node) - } - return nodes - } - - /** - * - * @param name - * @returns - */ - async getNodesWithName(name: string) { - const nodes: genericASTNode[] = [] - for (const node of Object.values(this.nodeIndex.flatReferences)) { - if (node.name === name) nodes.push(node) + } + } + } + + /** + * Nodes at position where position is a number, offset + * @param position + * @param type + * @returns + */ + async nodesAtPosition(position: number, type = ''): Promise { + let lastCompilationResult = this.compilerAbstract + if (this.debuggerIsOn) { + lastCompilationResult = await this.call('compilerArtefacts', 'get', '__last') + this.currentFile = await this.call('fileManager', 'file') + } + if (!lastCompilationResult) return [] + const urlFromPath = await this.call('fileManager', 'getUrlFromPath', this.currentFile) + if ( + lastCompilationResult && + lastCompilationResult.languageversion.indexOf('soljson') === 0 && + lastCompilationResult.data && + lastCompilationResult.data.sources && + lastCompilationResult.data.sources[this.currentFile] + ) { + const nodes: genericASTNode[] = sourceMappingDecoder.nodesAtPosition( + type, + position, + lastCompilationResult.data.sources[this.currentFile] || lastCompilationResult.data.sources[urlFromPath.file] + ) + return nodes + } + return [] + } + + /** + * + * @param id + * @returns + */ + async getNodeById(id: number) { + for (const key in this.nodeIndex.flatReferences) { + if (this.nodeIndex.flatReferences[key].id === id) { + return this.nodeIndex.flatReferences[key] + } + } + } + + /** + * + * @param id + * @returns + */ + async getDeclaration(id: number) { + if (this.nodeIndex.declarations && this.nodeIndex.declarations[id]) return this.nodeIndex.declarations[id] + } + + /** + * + * @param scope + * @returns + */ + async getNodesWithScope(scope: number) { + const nodes = [] + for (const node of Object.values(this.nodeIndex.flatReferences)) { + if (node.scope === scope) nodes.push(node) + } + return nodes + } + + /** + * + * @param name + * @returns + */ + async getNodesWithName(name: string) { + const nodes: genericASTNode[] = [] + for (const node of Object.values(this.nodeIndex.flatReferences)) { + if (node.name === name) nodes.push(node) + } + return nodes + } + /** + * + * @param node + * @returns + */ + declarationOf(node: T) { + if (node && 'referencedDeclaration' in node && node.referencedDeclaration) { + return this.nodeIndex.flatReferences[node.referencedDeclaration] + } + return null + } + + /** + * + * @param position + * @returns + */ + async definitionAtPosition(position: number) { + const nodes = await this.nodesAtPosition(position) + const nodeDefinition = { + 'ast': null, + 'parser': null + } + let node: genericASTNode + if (nodes && nodes.length) { + node = nodes[nodes.length - 1] + let astNodeDefinition = node + if (!isNodeDefinition(node)) { + astNodeDefinition = (await this.declarationOf(node)) || node + } + if (node.nodeType === 'ImportDirective') { + for (const key in this.nodeIndex.flatReferences) { + if (this.nodeIndex.flatReferences[key].id === node.sourceUnit) { + astNodeDefinition = this.nodeIndex.flatReferences[key] + } } - return nodes - } - /** - * - * @param node - * @returns - */ - declarationOf(node: T) { - if (node && ('referencedDeclaration' in node) && node.referencedDeclaration) { - return this.nodeIndex.flatReferences[node.referencedDeclaration] + } + + nodeDefinition.ast = astNodeDefinition + } + const astNodes = await this.antlrService.listAstNodes() + let parserNodeDefinition = null + if (astNodes && astNodes.length) { + for (const node of astNodes) { + if (node.range[0] <= position && node.range[1] >= position) { + if (parserNodeDefinition && parserNodeDefinition.range[0] < node.range[0]) { + parserNodeDefinition = node + } + if (!parserNodeDefinition) parserNodeDefinition = node } - return null - } - - /** - * - * @param position - * @returns - */ - async definitionAtPosition(position: number) { - const nodes = await this.nodesAtPosition(position) - let nodeDefinition: any - let node: genericASTNode - if (nodes && nodes.length && !this.errorState) { - node = nodes[nodes.length - 1] - nodeDefinition = node - if (!isNodeDefinition(node)) { - nodeDefinition = await this.declarationOf(node) || node - } - if (node.nodeType === 'ImportDirective') { - for (const key in this.nodeIndex.flatReferences) { - if (this.nodeIndex.flatReferences[key].id === node.sourceUnit) { - nodeDefinition = this.nodeIndex.flatReferences[key] - } - } - } - return nodeDefinition - } else { - const astNodes = await this.antlrService.listAstNodes() - if (astNodes && astNodes.length) { - for (const node of astNodes) { - if (node.range[0] <= position && node.range[1] >= position) { - if (nodeDefinition && nodeDefinition.range[0] < node.range[0]) { - nodeDefinition = node - } - if (!nodeDefinition) nodeDefinition = node - } - } - if (nodeDefinition && nodeDefinition.type && nodeDefinition.type === 'Identifier') { - const nodeForIdentifier = await this.findIdentifier(nodeDefinition) - if (nodeForIdentifier) nodeDefinition = nodeForIdentifier - } - return nodeDefinition - } - } - + } + if (parserNodeDefinition && parserNodeDefinition.type && parserNodeDefinition.type === 'Identifier') { + const nodeForIdentifier = await this.findIdentifier(parserNodeDefinition) + if (nodeForIdentifier) parserNodeDefinition = nodeForIdentifier + } + nodeDefinition.parser = parserNodeDefinition } - async getContractNodes(contractName: string) { - if (this.nodeIndex.nodesPerFile - && this.nodeIndex.nodesPerFile[this.currentFile] - && this.nodeIndex.nodesPerFile[this.currentFile].contracts[contractName] - && this.nodeIndex.nodesPerFile[this.currentFile].contracts[contractName].contractNodes) { - return this.nodeIndex.nodesPerFile[this.currentFile].contracts[contractName] - } - return false - } + /* if the AST node name & type is the same as the parser node name & type, + / then we can assume that the AST node is the definition, + / because the parser will always return most nodes it can find even with an error in the code + */ - async getCurrentFileNodes() { - if (this.nodeIndex.nodesPerFile - && this.nodeIndex.nodesPerFile[this.currentFile]) { - return this.nodeIndex.nodesPerFile[this.currentFile] - } - return false - } - - /** - * - * @param identifierNode - * @returns - */ - async findIdentifier(identifierNode: any) { - const astNodes = await this.antlrService.listAstNodes() - for (const node of astNodes) { - if (node.name === identifierNode.name && node.nodeType !== 'Identifier') { - return node - } + if (nodeDefinition.ast && nodeDefinition.parser) { + if (nodeDefinition.ast.name === nodeDefinition.parser.name && nodeDefinition.ast.nodeType === nodeDefinition.parser.type) { + return nodeDefinition.ast + }else{ + // if there is a difference and the compiler has compiled correctly assume the ast node is the definition + if(this.compilerService.errorState === false){ + return nodeDefinition.ast } + } } - /** - * - * @param node - * @returns - */ - async positionOfDefinition(node: genericASTNode): Promise { - if (node) { - if (node.src) { - const position = sourceMappingDecoder.decode(node.src) - if (position) { - return position - } - } - } - return null - } - - /** - * - * @param node - * @param imported - * @returns - */ - async resolveImports(node: any, imported = {}) { - if (node.nodeType === 'ImportDirective' && !imported[node.sourceUnit]) { - const importNode: any = await this.getNodeById(node.sourceUnit) - imported[importNode.id] = importNode - if (importNode.nodes) { - for (const child of importNode.nodes) { - imported = await this.resolveImports(child, imported) - } - } - } - return imported + if (nodeDefinition.ast && !nodeDefinition.parser) { + return nodeDefinition.ast } + return nodeDefinition.parser - /** - * - * @param node - * @returns - */ - referencesOf(node: genericASTNode) { - const results: genericASTNode[] = [] - const highlights = (id: number) => { - if (this.nodeIndex.declarations && this.nodeIndex.declarations[id]) { - const refs = this.nodeIndex.declarations[id] - for (const ref in refs) { - const node = refs[ref] - results.push(node) - } - } - } - if (node && ("referencedDeclaration" in node) && node.referencedDeclaration) { - highlights(node.referencedDeclaration) - const current = this.nodeIndex.flatReferences[node.referencedDeclaration] - results.push(current) - } else { - highlights(node.id) - } - return results - } - - /** - * - * @param position - * @returns - */ - async referrencesAtPosition(position: any): Promise { - const nodes = await this.nodesAtPosition(position) - if (nodes && nodes.length) { - const node = nodes[nodes.length - 1] - if (node) { - return this.referencesOf(node) - } - } - } + } - /** - * - * @returns - */ - async getNodes(): Promise { - return this.nodeIndex.flatReferences + async getContractNodes(contractName: string) { + if ( + this.nodeIndex.nodesPerFile && + this.nodeIndex.nodesPerFile[this.currentFile] && + this.nodeIndex.nodesPerFile[this.currentFile].contracts[contractName] && + this.nodeIndex.nodesPerFile[this.currentFile].contracts[contractName].contractNodes + ) { + return this.nodeIndex.nodesPerFile[this.currentFile].contracts[contractName] } + return false + } - - - /** - * - * @param node - * @returns - */ - async getNodeLink(node: genericASTNode) { - const lineColumn = await this.getLineColumnOfNode(node) - const position = await this.positionOfDefinition(node) - if (this.compilerAbstract && this.compilerAbstract.source && position) { - const fileName = this.compilerAbstract.getSourceName(position.file) - return lineColumn ? `${fileName} ${lineColumn.start.line}:${lineColumn.start.column}` : null - } - return '' + async getCurrentFileNodes() { + if (this.nodeIndex.nodesPerFile && this.nodeIndex.nodesPerFile[this.currentFile]) { + return this.nodeIndex.nodesPerFile[this.currentFile] } + return false + } - /* - * @param node - */ - async getLineColumnOfNode(node: any) { - const position = await this.positionOfDefinition(node) - return this.getLineColumnOfPosition(position) + /** + * + * @param identifierNode + * @returns + */ + async findIdentifier(identifierNode: any) { + const astNodes = await this.antlrService.listAstNodes() + for (const node of astNodes) { + if (node.name === identifierNode.name && node.nodeType !== 'Identifier') { + return node + } } + } - /* - * @param position - */ - async getLineColumnOfPosition(position: any) { + /** + * + * @param node + * @returns + */ + async positionOfDefinition(node: genericASTNode): Promise { + if (node) { + if (node.src) { + const position = sourceMappingDecoder.decode(node.src) if (position) { - const fileName = this.compilerAbstract.getSourceName(position.file) - const lineBreaks = sourceMappingDecoder.getLinebreakPositions(this.compilerAbstract.source.sources[fileName].content) - const lineColumn = sourceMappingDecoder.convertOffsetToLineColumn(position, lineBreaks) - return lineColumn - } - } - - /** - * - * @param node - * @returns - */ - async getNodeDocumentation(node: genericASTNode) { - if (("documentation" in node) && node.documentation && (node.documentation as any).text) { - let text = ''; - (node.documentation as any).text.split('\n').forEach(line => { - text += `${line.trim()}\n` - }) - return text - } - } - - /** - * - * @param node - * @returns - */ - async getVariableDeclaration(node: any) { - const nodeVisibility = node.visibility && node.visibility.length ? node.visibility + ' ' : '' - const nodeName = node.name && node.name.length ? node.name : '' - if (node.typeDescriptions && node.typeDescriptions.typeString) { - return `${node.typeDescriptions.typeString} ${nodeVisibility}${nodeName}` - } else { - if (node.typeName && node.typeName.name) { - return `${node.typeName.name} ${nodeVisibility}${nodeName}` - } - else if (node.typeName && node.typeName.namePath) { - return `${node.typeName.namePath} ${nodeVisibility}${nodeName}` - } - else { - return `${nodeName}${nodeName}` - } + return position } - } - - /** - * - * @param node - * @returns - */ - async getFunctionParamaters(node: any) { - const localParam = (node.parameters && node.parameters.parameters) || (node.parameters) - if (localParam) { - const params = [] - for (const param of localParam) { - params.push(await this.getVariableDeclaration(param)) - } - return `(${params.join(', ')})` + } + } + return null + } + + /** + * + * @param node + * @param imported + * @returns + */ + async resolveImports(node: any, imported = {}) { + if (node.nodeType === 'ImportDirective' && !imported[node.sourceUnit]) { + const importNode: any = await this.getNodeById(node.sourceUnit) + imported[importNode.id] = importNode + if (importNode.nodes) { + for (const child of importNode.nodes) { + imported = await this.resolveImports(child, imported) } - } - - /** - * - * @param node - * @returns - */ - async getFunctionReturnParameters(node: any) { - const localParam = (node.returnParameters && node.returnParameters.parameters) - if (localParam) { - const params = [] - for (const param of localParam) { - params.push(await this.getVariableDeclaration(param)) - } - return `(${params.join(', ')})` + } + } + return imported + } + + /** + * + * @param node + * @returns + */ + referencesOf(node: genericASTNode) { + const results: genericASTNode[] = [] + const highlights = (id: number) => { + if (this.nodeIndex.declarations && this.nodeIndex.declarations[id]) { + const refs = this.nodeIndex.declarations[id] + for (const ref in refs) { + const node = refs[ref] + results.push(node) } - } - - - + } + } + if (node && 'referencedDeclaration' in node && node.referencedDeclaration) { + highlights(node.referencedDeclaration) + const current = this.nodeIndex.flatReferences[node.referencedDeclaration] + results.push(current) + } else { + highlights(node.id) + } + return results + } + + /** + * + * @param position + * @returns + */ + async referrencesAtPosition(position: any): Promise { + const nodes = await this.nodesAtPosition(position) + if (nodes && nodes.length) { + const node = nodes[nodes.length - 1] + if (node) { + return this.referencesOf(node) + } + } + } + + /** + * + * @returns + */ + async getNodes(): Promise { + return this.nodeIndex.flatReferences + } + + /** + * + * @param node + * @returns + */ + async getNodeLink(node: genericASTNode) { + const lineColumn = await this.getLineColumnOfNode(node) + const position = await this.positionOfDefinition(node) + if (this.compilerAbstract && this.compilerAbstract.source && position) { + const fileName = this.compilerAbstract.getSourceName(position.file) + return lineColumn ? `${fileName} ${lineColumn.start.line}:${lineColumn.start.column}` : null + } + return '' + } + + /* + * @param node + */ + async getLineColumnOfNode(node: any) { + const position = await this.positionOfDefinition(node) + return this.getLineColumnOfPosition(position) + } + + /* + * @param position + */ + async getLineColumnOfPosition(position: any) { + if (position) { + const fileName = this.compilerAbstract.getSourceName(position.file) + const lineBreaks = sourceMappingDecoder.getLinebreakPositions(this.compilerAbstract.source.sources[fileName].content) + const lineColumn = sourceMappingDecoder.convertOffsetToLineColumn(position, lineBreaks) + return lineColumn + } + } + + /** + * + * @param node + * @returns + */ + async getNodeDocumentation(node: genericASTNode) { + if ('documentation' in node && node.documentation && (node.documentation as any).text) { + let text = '' + ;(node.documentation as any).text.split('\n').forEach((line) => { + text += `${line.trim()}\n` + }) + return text + } + } + + /** + * + * @param node + * @returns + */ + async getVariableDeclaration(node: any) { + const nodeVisibility = node.visibility && node.visibility.length ? node.visibility + ' ' : '' + const nodeName = node.name && node.name.length ? node.name : '' + if (node.typeDescriptions && node.typeDescriptions.typeString) { + return `${node.typeDescriptions.typeString} ${nodeVisibility}${nodeName}` + } else { + if (node.typeName && node.typeName.name) { + return `${node.typeName.name} ${nodeVisibility}${nodeName}` + } else if (node.typeName && node.typeName.namePath) { + return `${node.typeName.namePath} ${nodeVisibility}${nodeName}` + } else { + return `${nodeName}${nodeName}` + } + } + } + + /** + * + * @param node + * @returns + */ + async getFunctionParamaters(node: any) { + const localParam = (node.parameters && node.parameters.parameters) || node.parameters + if (localParam) { + const params = [] + for (const param of localParam) { + params.push(await this.getVariableDeclaration(param)) + } + return `(${params.join(', ')})` + } + } + + /** + * + * @param node + * @returns + */ + async getFunctionReturnParameters(node: any) { + const localParam = node.returnParameters && node.returnParameters.parameters + if (localParam) { + const params = [] + for (const param of localParam) { + params.push(await this.getVariableDeclaration(param)) + } + return `(${params.join(', ')})` + } + } } diff --git a/apps/remix-ide/src/app/plugins/parser/services/antlr-worker.ts b/apps/remix-ide/src/app/plugins/parser/services/antlr-worker.ts index 0b2b843c7e..c9e026d085 100644 --- a/apps/remix-ide/src/app/plugins/parser/services/antlr-worker.ts +++ b/apps/remix-ide/src/app/plugins/parser/services/antlr-worker.ts @@ -1,45 +1,45 @@ let parser: any self.onmessage = (e: MessageEvent) => { - const data: any = e.data - switch (data.cmd) { - case 'load': - { - (self as any).importScripts(e.data.url) - // @ts-ignore - parser = SolidityParser as any; + const data: any = e.data + switch (data.cmd) { + case 'load': + { + (self as any).importScripts(e.data.url) + // @ts-ignore + parser = SolidityParser as any; - self.postMessage({ - cmd: 'loaded', - }) - break - } + self.postMessage({ + cmd: 'loaded', + }) + break + } - case 'parse': - if (data.text && parser) { + case 'parse': + if (data.text && parser) { - try { - let startTime = performance.now() - const blocks = parser.parseBlock(data.text, { loc: true, range: true, tolerant: true }) - const blockDuration = performance.now() - startTime - startTime = performance.now() - const ast = parser.parse(data.text, { loc: true, range: true, tolerant: true }) - const endTime = performance.now() + try { + let startTime = performance.now() + const blocks = parser.parseBlock(data.text, { loc: true, range: true, tolerant: true }) + const blockDuration = performance.now() - startTime + startTime = performance.now() + const ast = parser.parse(data.text, { loc: true, range: true, tolerant: true }) + const endTime = performance.now() - self.postMessage({ - cmd: 'parsed', - timestamp: data.timestamp, - ast, - text: data.text, - file: data.file, - duration: endTime - startTime, - blockDuration, - blocks - }) - } catch (e) { - // do nothing - } + self.postMessage({ + cmd: 'parsed', + timestamp: data.timestamp, + ast, + text: data.text, + file: data.file, + duration: endTime - startTime, + blockDuration, + blocks + }) + } catch (e) { + // do nothing + } - } - break } + break + } } \ No newline at end of file diff --git a/apps/remix-ide/src/app/plugins/parser/services/code-parser-antlr-service.ts b/apps/remix-ide/src/app/plugins/parser/services/code-parser-antlr-service.ts index bbf5938e0c..5b70c27593 100644 --- a/apps/remix-ide/src/app/plugins/parser/services/code-parser-antlr-service.ts +++ b/apps/remix-ide/src/app/plugins/parser/services/code-parser-antlr-service.ts @@ -21,269 +21,268 @@ interface BlockDefinition { } export default class CodeParserAntlrService { - plugin: CodeParser - worker: Worker - parserStartTime: number = 0 - workerTimer: NodeJS.Timer - parserThreshold: number = 10 - parserThresholdSampleAmount = 3 - cache: { - [name: string]: { - text: string, - ast: antlr.ParseResult | null, - duration?: number, - parsingEnabled?: boolean, - blocks?: BlockDefinition[], - blockDurations?: number[] - } - } = {}; - constructor(plugin: CodeParser) { - this.plugin = plugin - this.createWorker() + plugin: CodeParser + worker: Worker + parserStartTime: number = 0 + workerTimer: NodeJS.Timer + parserThreshold: number = 10 + parserThresholdSampleAmount = 3 + cache: { + [name: string]: { + text: string + ast: antlr.ParseResult | null + duration?: number + parsingEnabled?: boolean + blocks?: BlockDefinition[] + blockDurations?: number[] } + } = {} + constructor(plugin: CodeParser) { + this.plugin = plugin + this.createWorker() + } - createWorker() { - this.worker = new Worker(new URL('./antlr-worker', import.meta.url)) - this.worker.postMessage({ - cmd: 'load', - url: isElectron()? 'assets/js/parser/antlr.js': document.location.protocol + '//' + document.location.host + '/assets/js/parser/antlr.js', - }); - const self = this + createWorker() { + this.worker = new Worker(new URL('./antlr-worker', import.meta.url)) + this.worker.postMessage({ + cmd: 'load', + url: isElectron() ? 'assets/js/parser/antlr.js' : document.location.protocol + '//' + document.location.host + '/assets/js/parser/antlr.js', + }) + const self = this - this.worker.addEventListener('message', function (ev) { - switch (ev.data.cmd) { - case 'parsed': - if (ev.data.ast && self.parserStartTime === ev.data.timestamp) { - self.cache[ev.data.file] = { - ...self.cache[ev.data.file], - text: ev.data.text, - ast: ev.data.ast, - duration: ev.data.duration, - blocks: ev.data.blocks, - blockDurations: self.cache[ev.data.file].blockDurations? [...self.cache[ev.data.file].blockDurations.slice(-self.parserThresholdSampleAmount), ev.data.blockDuration]: [ev.data.blockDuration] - } - self.setFileParsingState(ev.data.file) - } - break; + this.worker.addEventListener('message', function (ev) { + switch (ev.data.cmd) { + case 'parsed': + if (ev.data.ast && self.parserStartTime === ev.data.timestamp) { + self.cache[ev.data.file] = { + ...self.cache[ev.data.file], + text: ev.data.text, + ast: ev.data.ast, + duration: ev.data.duration, + blocks: ev.data.blocks, + blockDurations: self.cache[ev.data.file].blockDurations + ? [...self.cache[ev.data.file].blockDurations.slice(-self.parserThresholdSampleAmount), ev.data.blockDuration] + : [ev.data.blockDuration], } + self.setFileParsingState(ev.data.file) + } + break + } + }) + } - }); - } - - setFileParsingState(file: string) { - if (this.cache[file]) { - if (this.cache[file].blockDurations && this.cache[file].blockDurations.length > this.parserThresholdSampleAmount) { - // calculate average of durations to determine if the parsing should be disabled - const values = [...this.cache[file].blockDurations] - const average = values.reduce((a, b) => a + b, 0) / values.length - if (average > this.parserThreshold) { - this.cache[file].parsingEnabled = false - } else { - this.cache[file].parsingEnabled = true - } - } - } - } - - enableWorker() { - if (!this.workerTimer) { - this.workerTimer = setInterval(() => { - this.setCurrentFileAST() - }, 5000) + setFileParsingState(file: string) { + if (this.cache[file]) { + if (this.cache[file].blockDurations && this.cache[file].blockDurations.length > this.parserThresholdSampleAmount) { + // calculate average of durations to determine if the parsing should be disabled + const values = [...this.cache[file].blockDurations] + const average = values.reduce((a, b) => a + b, 0) / values.length + if (average > this.parserThreshold) { + this.cache[file].parsingEnabled = false + } else { + this.cache[file].parsingEnabled = true } + } } + } - disableWorker() { - clearInterval(this.workerTimer) + enableWorker() { + if (!this.workerTimer) { + this.workerTimer = setInterval(() => { + this.setCurrentFileAST() + }, 5000) } + } + disableWorker() { + clearInterval(this.workerTimer) + } - async parseWithWorker(text: string, file: string) { - this.parserStartTime = Date.now() - this.worker.postMessage({ - cmd: 'parse', - text, - timestamp: this.parserStartTime, - file, - parsingEnabled: (this.cache[file] && this.cache[file].parsingEnabled) || true - }); + async parseWithWorker(text: string, file: string) { + this.parserStartTime = Date.now() + this.worker.postMessage({ + cmd: 'parse', + text, + timestamp: this.parserStartTime, + file, + parsingEnabled: (this.cache[file] && this.cache[file].parsingEnabled) || true, + }) + } - } - - async parseSolidity(text: string) { - const ast: antlr.ParseResult = (SolidityParser as any).parse(text, { loc: true, range: true, tolerant: true }) - return ast - } + async parseSolidity(text: string) { + const ast: antlr.ParseResult = (SolidityParser as any).parse(text, { loc: true, range: true, tolerant: true }) + return ast + } - /** - * Tries to parse the current file or the given text and returns the AST - * If the parsing fails it returns the last successful AST for this file - * @param text - * @returns - */ - async setCurrentFileAST(text: string | null = null) { - try { - this.plugin.currentFile = await this.plugin.call('fileManager', 'file') - if (this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) { - const fileContent = text || await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile) - if (!this.cache[this.plugin.currentFile]) { - this.cache[this.plugin.currentFile] = { - text: '', - ast: null, - parsingEnabled: true, - blockDurations: [] - } - } - if (this.cache[this.plugin.currentFile] && this.cache[this.plugin.currentFile].text !== fileContent) { - try { - await this.parseWithWorker(fileContent, this.plugin.currentFile) - } catch (e) { - // do nothing - } - } - } - } catch (e) { + /** + * Tries to parse the current file or the given text and returns the AST + * If the parsing fails it returns the last successful AST for this file + * @param text + * @returns + */ + async setCurrentFileAST(text: string | null = null) { + try { + this.plugin.currentFile = await this.plugin.call('fileManager', 'file') + if (this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) { + const fileContent = text || (await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile)) + if (!this.cache[this.plugin.currentFile]) { + this.cache[this.plugin.currentFile] = { + text: '', + ast: null, + parsingEnabled: true, + blockDurations: [], + } + } + if (this.cache[this.plugin.currentFile] && this.cache[this.plugin.currentFile].text !== fileContent) { + try { + await this.parseWithWorker(fileContent, this.plugin.currentFile) + } catch (e) { // do nothing + } } + } + } catch (e) { + // do nothing } + } - /** - * Lists the AST nodes from the current file parser - * These nodes need to be changed to match the node types returned by the compiler - * @returns - */ - async listAstNodes() { - this.plugin.currentFile = await this.plugin.call('fileManager', 'file') - if (!this.cache[this.plugin.currentFile]) return - const nodes: AstNode[] = []; - (SolidityParser as any).visit(this.cache[this.plugin.currentFile].ast, { - StateVariableDeclaration: (node: antlr.StateVariableDeclaration) => { - if (node.variables) { - for (const variable of node.variables) { - nodes.push({ ...variable, nodeType: 'VariableDeclaration', id: null, src: null }) - } - } - }, - VariableDeclaration: (node: antlr.VariableDeclaration) => { - nodes.push({ ...node, nodeType: node.type, id: null, src: null }) - }, - UserDefinedTypeName: (node: antlr.UserDefinedTypeName) => { - nodes.push({ ...node, nodeType: node.type, id: null, src: null }) - }, - FunctionDefinition: (node: antlr.FunctionDefinition) => { - nodes.push({ ...node, nodeType: node.type, id: null, src: null }) - }, - ContractDefinition: (node: antlr.ContractDefinition) => { - nodes.push({ ...node, nodeType: node.type, id: null, src: null }) - }, - MemberAccess: function (node: antlr.MemberAccess) { - nodes.push({ ...node, nodeType: node.type, id: null, src: null }) - }, - Identifier: function (node: antlr.Identifier) { - nodes.push({ ...node, nodeType: node.type, id: null, src: null }) - }, - EventDefinition: function (node: antlr.EventDefinition) { - nodes.push({ ...node, nodeType: node.type, id: null, src: null }) - }, - ModifierDefinition: function (node: antlr.ModifierDefinition) { - nodes.push({ ...node, nodeType: node.type, id: null, src: null }) - }, - InvalidNode: function (node: antlr.InvalidNode) { - nodes.push({ ...node, nodeType: node.type, id: null, src: null }) - }, - EnumDefinition: function (node: antlr.EnumDefinition) { - nodes.push({ ...node, nodeType: node.type, id: null, src: null }) - }, - StructDefinition: function (node: antlr.StructDefinition) { - nodes.push({ ...node, nodeType: node.type, id: null, src: null }) - } - - }) - return nodes - } - - - /** - * - * @param ast - * @returns - */ - async getLastNodeInLine(ast: string) { - let lastNode: any - const checkLastNode = (node: antlr.MemberAccess | antlr.Identifier) => { - if (lastNode && lastNode.range && lastNode.range[1]) { - if (node.range[1] > lastNode.range[1]) { - lastNode = node - } - } else { - lastNode = node - } + /** + * Lists the AST nodes from the current file parser + * These nodes need to be changed to match the node types returned by the compiler + * @returns + */ + async listAstNodes() { + this.plugin.currentFile = await this.plugin.call('fileManager', 'file') + if (!this.cache[this.plugin.currentFile]) return + const nodes: AstNode[] = [] + ;(SolidityParser as any).visit(this.cache[this.plugin.currentFile].ast, { + StateVariableDeclaration: (node: antlr.StateVariableDeclaration) => { + if (node.variables) { + for (const variable of node.variables) { + nodes.push({ ...variable, nodeType: 'VariableDeclaration', id: null, src: null }) + } } + }, + VariableDeclaration: (node: antlr.VariableDeclaration) => { + nodes.push({ ...node, nodeType: node.type, id: null, src: null }) + }, + UserDefinedTypeName: (node: antlr.UserDefinedTypeName) => { + nodes.push({ ...node, nodeType: node.type, id: null, src: null }) + }, + FunctionDefinition: (node: antlr.FunctionDefinition) => { + nodes.push({ ...node, nodeType: node.type, id: null, src: null }) + }, + ContractDefinition: (node: antlr.ContractDefinition) => { + nodes.push({ ...node, nodeType: node.type, id: null, src: null }) + }, + MemberAccess: function (node: antlr.MemberAccess) { + nodes.push({ ...node, nodeType: node.type, id: null, src: null }) + }, + Identifier: function (node: antlr.Identifier) { + nodes.push({ ...node, nodeType: node.type, id: null, src: null }) + }, + EventDefinition: function (node: antlr.EventDefinition) { + nodes.push({ ...node, nodeType: node.type, id: null, src: null }) + }, + ModifierDefinition: function (node: antlr.ModifierDefinition) { + nodes.push({ ...node, nodeType: node.type, id: null, src: null }) + }, + InvalidNode: function (node: antlr.InvalidNode) { + nodes.push({ ...node, nodeType: node.type, id: null, src: null }) + }, + EnumDefinition: function (node: antlr.EnumDefinition) { + nodes.push({ ...node, nodeType: node.type, id: null, src: null }) + }, + StructDefinition: function (node: antlr.StructDefinition) { + nodes.push({ ...node, nodeType: node.type, id: null, src: null }) + }, + }) + return nodes + } - (SolidityParser as any).visit(ast, { - MemberAccess: function (node: antlr.MemberAccess) { - checkLastNode(node) - }, - Identifier: function (node: antlr.Identifier) { - checkLastNode(node) - } - }) - if (lastNode && lastNode.expression) { - return lastNode.expression + /** + * + * @param ast + * @returns + */ + async getLastNodeInLine(ast: string) { + let lastNode: any + const checkLastNode = (node: antlr.MemberAccess | antlr.Identifier) => { + if (lastNode && lastNode.range && lastNode.range[1]) { + if (node.range[1] > lastNode.range[1]) { + lastNode = node } - return lastNode + } else { + lastNode = node + } } - /* - * get the code blocks of the current file - */ - async getCurrentFileBlocks(text: string | null = null) { - this.plugin.currentFile = await this.plugin.call('fileManager', 'file') - if (this.cache[this.plugin.currentFile]) { - if (!this.cache[this.plugin.currentFile].parsingEnabled) { - return - } - } - if (this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) { - const fileContent = text || await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile) - try { - const startTime = Date.now() - const blocks = (SolidityParser as any).parseBlock(fileContent, { loc: true, range: true, tolerant: true }) - if(this.cache[this.plugin.currentFile] && this.cache[this.plugin.currentFile].blockDurations){ - this.cache[this.plugin.currentFile].blockDurations = [...this.cache[this.plugin.currentFile].blockDurations.slice(-this.parserThresholdSampleAmount), Date.now() - startTime] - this.setFileParsingState(this.plugin.currentFile) - } - if (blocks) this.cache[this.plugin.currentFile].blocks = blocks - return blocks - } catch (e) { - // do nothing - } + + ;(SolidityParser as any).visit(ast, { + MemberAccess: function (node: antlr.MemberAccess) { + checkLastNode(node) + }, + Identifier: function (node: antlr.Identifier) { + checkLastNode(node) + }, + }) + if (lastNode && lastNode.expression) { + return lastNode.expression + } + return lastNode + } + /* + * get the code blocks of the current file + */ + async getCurrentFileBlocks(text: string | null = null) { + this.plugin.currentFile = await this.plugin.call('fileManager', 'file') + if (this.cache[this.plugin.currentFile]) { + if (!this.cache[this.plugin.currentFile].parsingEnabled) { + return + } + } + if (this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) { + const fileContent = text || (await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile)) + try { + const startTime = Date.now() + const blocks = (SolidityParser as any).parseBlock(fileContent, { loc: true, range: true, tolerant: true }) + if (this.cache[this.plugin.currentFile] && this.cache[this.plugin.currentFile].blockDurations) { + this.cache[this.plugin.currentFile].blockDurations = [ + ...this.cache[this.plugin.currentFile].blockDurations.slice(-this.parserThresholdSampleAmount), + Date.now() - startTime, + ] + this.setFileParsingState(this.plugin.currentFile) } + if (blocks) this.cache[this.plugin.currentFile].blocks = blocks + return blocks + } catch (e) { + // do nothing + } } + } - /** - * Returns the block surrounding the given position - * For example if the position is in the middle of a function, it will return the function - * @param {position} position - * @param {string} text // optional - * @return {any} - * */ - async getANTLRBlockAtPosition(position: any, text: string = null) { - const blocks: any[] = await this.getCurrentFileBlocks(text) + /** + * Returns the block surrounding the given position + * For example if the position is in the middle of a function, it will return the function + * @param {position} position + * @param {string} text // optional + * @return {any} + * */ + async getANTLRBlockAtPosition(position: any, text: string = null) { + const blocks: any[] = await this.getCurrentFileBlocks(text) - const walkAst = (blocks) => { - let nodeFound = null - for (const object of blocks) { - if (object.start <= position) { - nodeFound = object - break - } - } - return nodeFound + const walkAst = (blocks) => { + let nodeFound = null + for (const object of blocks) { + if (object.start <= position) { + nodeFound = object + break } - if (!blocks) return - blocks.reverse() - const block = walkAst(blocks) - return block + } + return nodeFound } - + if (!blocks) return + blocks.reverse() + const block = walkAst(blocks) + return block + } } diff --git a/apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts b/apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts index 42c718db2a..ecd8278ca3 100644 --- a/apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts +++ b/apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts @@ -34,253 +34,256 @@ type errorMarker = { file: string } export default class CodeParserCompiler { + plugin: CodeParser + compiler: any // used to compile the current file seperately from the main compiler + onAstFinished: (success: any, data: CompilationResult, source: CompilationSourceCode, input: any, version: any) => Promise; + errorState: boolean; + gastEstimateTimeOut: any + constructor( plugin: CodeParser - compiler: any // used to compile the current file seperately from the main compiler - onAstFinished: (success: any, data: CompilationResult, source: CompilationSourceCode, input: any, version: any) => Promise; - errorState: boolean; - gastEstimateTimeOut: any - constructor( - plugin: CodeParser - ) { - this.plugin = plugin - } - - init() { + ) { + this.plugin = plugin + } - this.onAstFinished = async (success, data: CompilationResult, source: CompilationSourceCode, input: any, version) => { - this.plugin.call('editor', 'clearAnnotations') - this.errorState = true - const result = new CompilerAbstract('soljson', data, source, input) - let allErrors: errorMarker[] = [] - if (data.errors || data.error) { - const file = await this.plugin.call('fileManager', 'getCurrentFile') - const currentFileContent = await this.plugin.call('fileManager', 'readFile', file) - const sources = result.getSourceCode().sources || [] - if (data.error) { - if (data.error.formattedMessage) { - // mark this file as error - const errorMarker = await this.createErrorMarker(data.error, file, { start: { line: 0, column: 0 }, end: { line: 0, column: 100 } }) - allErrors = [...allErrors, errorMarker] - } - } else { - for (const error of data.errors) { - if (!error.sourceLocation) { - // mark this file as error - const errorMarker = await this.createErrorMarker(error, file, { start: { line: 0, column: 0 }, end: { line: 0, column: 100 } }) - allErrors = [...allErrors, errorMarker] - } else { - const lineBreaks = sourceMappingDecoder.getLinebreakPositions(sources[error.sourceLocation.file].content) - const lineColumn = sourceMappingDecoder.convertOffsetToLineColumn({ - start: error.sourceLocation.start, - length: error.sourceLocation.end - error.sourceLocation.start - }, lineBreaks) + init() { + this.onAstFinished = async (success, data: CompilationResult, source: CompilationSourceCode, input: any, version) => { + this.plugin.call('editor', 'clearAnnotations') + this.errorState = true + const result = new CompilerAbstract('soljson', data, source, input) + let allErrors: errorMarker[] = [] + if (data.errors || data.error) { + const file = await this.plugin.call('fileManager', 'getCurrentFile') + const currentFileContent = await this.plugin.call('fileManager', 'readFile', file) + const sources = result.getSourceCode().sources || [] + if (data.error) { + if (data.error.formattedMessage) { + // mark this file as error + const errorMarker = await this.createErrorMarker(data.error, file, { start: { line: 0, column: 0 }, end: { line: 0, column: 100 } }) + allErrors = [...allErrors, errorMarker] + } + } else { + for (const error of data.errors) { + if (!error.sourceLocation) { + // mark this file as error + const errorMarker = await this.createErrorMarker(error, file, { start: { line: 0, column: 0 }, end: { line: 0, column: 100 } }) + allErrors = [...allErrors, errorMarker] + } else { + const lineBreaks = sourceMappingDecoder.getLinebreakPositions(sources[error.sourceLocation.file].content) + const lineColumn = sourceMappingDecoder.convertOffsetToLineColumn({ + start: error.sourceLocation.start, + length: error.sourceLocation.end - error.sourceLocation.start + }, lineBreaks) - const filePath = error.sourceLocation.file - const fileTarget = await this.plugin.call('fileManager', 'getUrlFromPath', filePath) - const importFilePositions = await this.getPositionForImportErrors(fileTarget.file, currentFileContent) - for (const importFilePosition of importFilePositions) { - for (const line of importFilePosition.lines) { - allErrors = [...allErrors, await this.createErrorMarker(error, file, line.position)] - } - } + const filePath = error.sourceLocation.file + const fileTarget = await this.plugin.call('fileManager', 'getUrlFromPath', filePath) - allErrors = [...allErrors, await this.createErrorMarker(error, filePath, lineColumn)] - } - } + const importFilePositions = await this.getPositionForImportErrors(fileTarget.file, currentFileContent) + for (const importFilePosition of importFilePositions) { + for (const line of importFilePosition.lines) { + allErrors = [...allErrors, await this.createErrorMarker(error, file, line.position)] } + } - const displayErrors = await this.plugin.call('config', 'getAppParameter', 'display-errors') - if (displayErrors) await this.plugin.call('editor', 'addErrorMarker', allErrors) - this.addDecorators(allErrors, sources) - } else { - await this.plugin.call('editor', 'clearErrorMarkers', result.getSourceCode().sources) - await this.clearDecorators(result.getSourceCode().sources) + allErrors = [...allErrors, await this.createErrorMarker(error, filePath, lineColumn)] } + } + } + const displayErrors = await this.plugin.call('config', 'getAppParameter', 'display-errors') + if (displayErrors) await this.plugin.call('editor', 'addErrorMarker', allErrors) + this.addDecorators(allErrors, sources) + } else { + await this.plugin.call('editor', 'clearErrorMarkers', result.getSourceCode().sources) + await this.clearDecorators(result.getSourceCode().sources) + } - if (!data.sources) return - if (data.sources && Object.keys(data.sources).length === 0) return - this.plugin.compilerAbstract = new CompilerAbstract('soljson', data, source, input) - this.errorState = false - this.plugin.nodeIndex = { - declarations: {}, - flatReferences: {}, - nodesPerFile: {}, - } - + if (!data.sources) return + if (data.sources && Object.keys(data.sources).length === 0) return + this.plugin.compilerAbstract = new CompilerAbstract('soljson', data, source, input) + this.errorState = false + + this.plugin.nodeIndex = { + declarations: {}, + flatReferences: {}, + nodesPerFile: {}, + } + - this.plugin._buildIndex(data, source) - // cast from the remix-plugin interface to the solidity one. Should be fixed when remix-plugin move to the remix-project repository - this.plugin.nodeIndex.nodesPerFile[this.plugin.currentFile] = this.plugin._extractFileNodes(this.plugin.currentFile, this.plugin.compilerAbstract as unknown as lastCompilationResult) - await this.plugin.gasService.showGasEstimates() - this.plugin.emit('astFinished') - } - - this.compiler = new Compiler((url, cb) => this.plugin.call('contentImport', 'resolveAndSave', url, undefined).then((result) => cb(null, result)).catch((error) => cb(error.message))) - this.compiler.event.register('compilationFinished', this.onAstFinished) + this.plugin._buildIndex(data, source) + // cast from the remix-plugin interface to the solidity one. Should be fixed when remix-plugin move to the remix-project repository + const extractedFiledNodes = this.plugin._extractFileNodes(this.plugin.currentFile, this.plugin.compilerAbstract as unknown as lastCompilationResult) + if(extractedFiledNodes) { + this.plugin.nodeIndex.nodesPerFile[this.plugin.currentFile] = extractedFiledNodes + } + await this.plugin.gasService.showGasEstimates() + this.plugin.emit('astFinished') } + + this.compiler = new Compiler((url, cb) => this.plugin.call('contentImport', 'resolveAndSave', url, undefined).then((result) => cb(null, result)).catch((error) => cb(error.message))) + this.compiler.event.register('compilationFinished', this.onAstFinished) + } - // COMPILER + // COMPILER - /** + /** * * @returns */ - async compile() { - try { - this.plugin.currentFile = await this.plugin.call('fileManager', 'file') - if (this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) { - const state = await this.plugin.call('solidity', 'getCompilerState') - this.compiler.set('optimize', state.optimize) - this.compiler.set('evmVersion', state.evmVersion) - this.compiler.set('language', state.language) - this.compiler.set('runs', state.runs) - this.compiler.set('useFileConfiguration', true) - this.compiler.set('compilerRetriggerMode', CompilerRetriggerMode.retrigger) - const configFileContent = { - "language": "Solidity", - "settings": { - "optimizer": { - "enabled": state.optimize, - "runs": state.runs - }, - "outputSelection": { - "*": { - "": ["ast"], - "*": ["evm.gasEstimates"] - } - }, - "evmVersion": state.evmVersion && state.evmVersion.toString() || "berlin", - } - } - - this.compiler.set('configFileContent', JSON.stringify(configFileContent)) - this.plugin.currentFile = await this.plugin.call('fileManager', 'file') - if (!this.plugin.currentFile) return - const content = await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile) - const sources = { [this.plugin.currentFile]: { content } } - this.compiler.compile(sources, this.plugin.currentFile) - } - } catch (e) { - // do nothing + async compile() { + try { + this.plugin.currentFile = await this.plugin.call('fileManager', 'file') + if (this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) { + const state = await this.plugin.call('solidity', 'getCompilerState') + this.compiler.set('optimize', state.optimize) + this.compiler.set('evmVersion', state.evmVersion) + this.compiler.set('language', state.language) + this.compiler.set('runs', state.runs) + this.compiler.set('useFileConfiguration', true) + this.compiler.set('compilerRetriggerMode', CompilerRetriggerMode.retrigger) + const configFileContent = { + "language": "Solidity", + "settings": { + "optimizer": { + "enabled": state.optimize, + "runs": state.runs + }, + "outputSelection": { + "*": { + "": ["ast"], + "*": ["evm.gasEstimates"] + } + }, + "evmVersion": state.evmVersion && state.evmVersion.toString() || "berlin", + } } - } - async addDecorators(allErrors: errorMarker[], sources: any) { - const displayErrors = await this.plugin.call('config', 'getAppParameter', 'display-errors') - if (!displayErrors) return - const errorsPerFiles: { [fileName: string]: errorMarker[] } = {} - for (const error of allErrors) { - if (!errorsPerFiles[error.file]) { - errorsPerFiles[error.file] = [] - } - errorsPerFiles[error.file].push(error) - } + this.compiler.set('configFileContent', JSON.stringify(configFileContent)) + this.plugin.currentFile = await this.plugin.call('fileManager', 'file') + if (!this.plugin.currentFile) return + const content = await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile) + const sources = { [this.plugin.currentFile]: { content } } + this.compiler.compile(sources, this.plugin.currentFile) + } + } catch (e) { + // do nothing + } + } - const errorPriority = { - 'error': 0, - 'warning': 1, - } + async addDecorators(allErrors: errorMarker[], sources: any) { + const displayErrors = await this.plugin.call('config', 'getAppParameter', 'display-errors') + if (!displayErrors) return + const errorsPerFiles: { [fileName: string]: errorMarker[] } = {} + for (const error of allErrors) { + if (!errorsPerFiles[error.file]) { + errorsPerFiles[error.file] = [] + } + errorsPerFiles[error.file].push(error) + } - // sort errorPerFiles by error priority - const sortedErrorsPerFiles: { [fileName: string]: errorMarker[] } = {} - for (const fileName in errorsPerFiles) { - const errors = errorsPerFiles[fileName] - errors.sort((a, b) => { - return errorPriority[a.severity] - errorPriority[b.severity] - } - ) - sortedErrorsPerFiles[fileName] = errors - } - const filesWithOutErrors = Object.keys(sources).filter((fileName) => !sortedErrorsPerFiles[fileName]) - // add decorators - const decorators: fileDecoration[] = [] - for (const fileName in sortedErrorsPerFiles) { - const errors = sortedErrorsPerFiles[fileName] - const fileTarget = await this.plugin.call('fileManager', 'getPathFromUrl', fileName) - const decorator: fileDecoration = { - path: fileTarget.file, - isDirectory: false, - fileStateType: errors[0].severity == MarkerSeverity.Error ? fileDecorationType.Error : fileDecorationType.Warning, - fileStateLabelClass: errors[0].severity == MarkerSeverity.Error ? 'text-danger' : 'text-warning', - fileStateIconClass: '', - fileStateIcon: '', - text: errors.length.toString(), - owner: 'code-parser', - bubble: true, - comment: errors.map((error) => error.message), - } - decorators.push(decorator) - } - for (const fileName of filesWithOutErrors) { - const fileTarget = await this.plugin.call('fileManager', 'getPathFromUrl', fileName) - const decorator: fileDecoration = { - path: fileTarget.file, - isDirectory: false, - fileStateType: fileDecorationType.None, - fileStateLabelClass: '', - fileStateIconClass: '', - fileStateIcon: '', - text: '', - owner: 'code-parser', - bubble: false - } - decorators.push(decorator) - } - await this.plugin.call('fileDecorator', 'setFileDecorators', decorators) - await this.plugin.call('editor', 'clearErrorMarkers', filesWithOutErrors) + const errorPriority = { + 'error': 0, + 'warning': 1, + } + // sort errorPerFiles by error priority + const sortedErrorsPerFiles: { [fileName: string]: errorMarker[] } = {} + for (const fileName in errorsPerFiles) { + const errors = errorsPerFiles[fileName] + errors.sort((a, b) => { + return errorPriority[a.severity] - errorPriority[b.severity] + } + ) + sortedErrorsPerFiles[fileName] = errors + } + const filesWithOutErrors = Object.keys(sources).filter((fileName) => !sortedErrorsPerFiles[fileName]) + // add decorators + const decorators: fileDecoration[] = [] + for (const fileName in sortedErrorsPerFiles) { + const errors = sortedErrorsPerFiles[fileName] + const fileTarget = await this.plugin.call('fileManager', 'getPathFromUrl', fileName) + const decorator: fileDecoration = { + path: fileTarget.file, + isDirectory: false, + fileStateType: errors[0].severity == MarkerSeverity.Error ? fileDecorationType.Error : fileDecorationType.Warning, + fileStateLabelClass: errors[0].severity == MarkerSeverity.Error ? 'text-danger' : 'text-warning', + fileStateIconClass: '', + fileStateIcon: '', + text: errors.length.toString(), + owner: 'code-parser', + bubble: true, + comment: errors.map((error) => error.message), + } + decorators.push(decorator) } + for (const fileName of filesWithOutErrors) { + const fileTarget = await this.plugin.call('fileManager', 'getPathFromUrl', fileName) + const decorator: fileDecoration = { + path: fileTarget.file, + isDirectory: false, + fileStateType: fileDecorationType.None, + fileStateLabelClass: '', + fileStateIconClass: '', + fileStateIcon: '', + text: '', + owner: 'code-parser', + bubble: false + } + decorators.push(decorator) + } + await this.plugin.call('fileDecorator', 'setFileDecorators', decorators) + await this.plugin.call('editor', 'clearErrorMarkers', filesWithOutErrors) - async createErrorMarker(error: any, filePath: string, lineColumn): Promise { - return { - message: error.formattedMessage, - severity: error.severity === 'error' ? MarkerSeverity.Error : MarkerSeverity.Warning, - position: { - start: { - line: ((lineColumn.start && lineColumn.start.line) || 0) + 1, - column: ((lineColumn.start && lineColumn.start.column) || 0) + 1 - }, - end: { - line: ((lineColumn.end && lineColumn.end.line) || 0) + 1, - column: ((lineColumn.end && lineColumn.end.column) || 0) + 1 - } - } - , file: filePath + } + + async createErrorMarker(error: any, filePath: string, lineColumn): Promise { + return { + message: error.formattedMessage, + severity: error.severity === 'error' ? MarkerSeverity.Error : MarkerSeverity.Warning, + position: { + start: { + line: ((lineColumn.start && lineColumn.start.line) || 0) + 1, + column: ((lineColumn.start && lineColumn.start.column) || 0) + 1 + }, + end: { + line: ((lineColumn.end && lineColumn.end.line) || 0) + 1, + column: ((lineColumn.end && lineColumn.end.column) || 0) + 1 } + } + , file: filePath } + } - async clearDecorators(sources: any) { - const decorators: fileDecoration[] = [] - if (!sources) return - for (const fileName of Object.keys(sources)) { - const decorator: fileDecoration = { - path: fileName, - isDirectory: false, - fileStateType: fileDecorationType.None, - fileStateLabelClass: '', - fileStateIconClass: '', - fileStateIcon: '', - text: '', - owner: 'code-parser', - bubble: false - } - decorators.push(decorator) - } + async clearDecorators(sources: any) { + const decorators: fileDecoration[] = [] + if (!sources) return + for (const fileName of Object.keys(sources)) { + const decorator: fileDecoration = { + path: fileName, + isDirectory: false, + fileStateType: fileDecorationType.None, + fileStateLabelClass: '', + fileStateIconClass: '', + fileStateIcon: '', + text: '', + owner: 'code-parser', + bubble: false + } + decorators.push(decorator) + } - await this.plugin.call('fileDecorator', 'setFileDecorators', decorators) - } + await this.plugin.call('fileDecorator', 'setFileDecorators', decorators) + } - async getPositionForImportErrors(importedFileName: string, text: string) { - const re = new RegExp(importedFileName, 'gi') - const result: SearchResultLine[] = findLinesInStringWithMatch( - text, - re - ) - return result - } + async getPositionForImportErrors(importedFileName: string, text: string) { + const re = new RegExp(importedFileName, 'gi') + const result: SearchResultLine[] = findLinesInStringWithMatch( + text, + re + ) + return result + } } \ No newline at end of file diff --git a/apps/remix-ide/src/app/plugins/parser/services/code-parser-gas-service.ts b/apps/remix-ide/src/app/plugins/parser/services/code-parser-gas-service.ts index 879d00f06d..34e86290c1 100644 --- a/apps/remix-ide/src/app/plugins/parser/services/code-parser-gas-service.ts +++ b/apps/remix-ide/src/app/plugins/parser/services/code-parser-gas-service.ts @@ -3,76 +3,79 @@ import { lineText } from '@remix-ui/editor' import { lastCompilationResult } from '@remixproject/plugin-api'; export default class CodeParserGasService { - plugin: CodeParser + plugin: CodeParser - constructor(plugin: CodeParser) { - this.plugin = plugin - } + constructor(plugin: CodeParser) { + this.plugin = plugin + } - async getGasEstimates(fileName: string) { - if (!fileName) { - fileName = await this.plugin.currentFile - } - if (this.plugin.nodeIndex.nodesPerFile && this.plugin.nodeIndex.nodesPerFile[fileName] && this.plugin.nodeIndex.nodesPerFile[fileName].contracts) { - const estimates: any = [] - for (const contract in this.plugin.nodeIndex.nodesPerFile[fileName].contracts) { - if (this.plugin.nodeIndex.nodesPerFile[fileName].contracts[contract].contractNodes) { - const nodes = this.plugin.nodeIndex.nodesPerFile[fileName].contracts[contract].contractNodes - for (const node of Object.values(nodes) as any[]) { - if (node.gasEstimate) { - estimates.push({ - node, - range: await this.plugin.getLineColumnOfNode(node) - }) - } - } - } + async getGasEstimates(fileName: string) { + if (!fileName) { + fileName = await this.plugin.currentFile + } + if (this.plugin.nodeIndex.nodesPerFile && this.plugin.nodeIndex.nodesPerFile[fileName] && this.plugin.nodeIndex.nodesPerFile[fileName].contracts) { + const estimates: any = [] + for (const contract in this.plugin.nodeIndex.nodesPerFile[fileName].contracts) { + if (this.plugin.nodeIndex.nodesPerFile[fileName].contracts[contract].contractNodes) { + const nodes = this.plugin.nodeIndex.nodesPerFile[fileName].contracts[contract].contractNodes + for (const node of Object.values(nodes) as any[]) { + if (node.gasEstimate) { + estimates.push({ + node, + range: await this.plugin.getLineColumnOfNode(node) + }) } - return estimates + } } - + } + return estimates } + } - async showGasEstimates() { - const showGasConfig = await this.plugin.call('config', 'getAppParameter', 'show-gas') - if(!showGasConfig) { - await this.plugin.call('editor', 'discardLineTexts') - return - } - this.plugin.currentFile = await this.plugin.call('fileManager', 'file') - // cast from the remix-plugin interface to the solidity one. Should be fixed when remix-plugin move to the remix-project repository - this.plugin.nodeIndex.nodesPerFile[this.plugin.currentFile] = await this.plugin._extractFileNodes(this.plugin.currentFile, this.plugin.compilerAbstract as unknown as lastCompilationResult) - const gasEstimates = await this.getGasEstimates(this.plugin.currentFile) + async showGasEstimates() { + const showGasConfig = await this.plugin.call('config', 'getAppParameter', 'show-gas') + if(!showGasConfig) { + await this.plugin.call('editor', 'discardLineTexts') + return + } + this.plugin.currentFile = await this.plugin.call('fileManager', 'file') + // cast from the remix-plugin interface to the solidity one. Should be fixed when remix-plugin move to the remix-project repository + const extractedFiledNodes = await this.plugin._extractFileNodes(this.plugin.currentFile, this.plugin.compilerAbstract as unknown as lastCompilationResult) + if(extractedFiledNodes) { + this.plugin.nodeIndex.nodesPerFile[this.plugin.currentFile] = extractedFiledNodes + } + + const gasEstimates = await this.getGasEstimates(this.plugin.currentFile) - const friendlyNames = { - 'executionCost': 'Estimated execution cost', - 'codeDepositCost': 'Estimated code deposit cost', - 'creationCost': 'Estimated creation cost', + const friendlyNames = { + 'executionCost': 'Estimated execution cost', + 'codeDepositCost': 'Estimated code deposit cost', + 'creationCost': 'Estimated creation cost', + } + await this.plugin.call('editor', 'discardLineTexts') + if (gasEstimates) { + for (const estimate of gasEstimates) { + const linetext: lineText = { + content: Object.entries(estimate.node.gasEstimate).map(([, value]) => `${value} gas`).join(' '), + position: estimate.range, + hide: false, + className: 'text-muted small', + afterContentClassName: 'text-muted small fas fa-gas-pump pl-4', + from: 'codeParser', + hoverMessage: [{ + value: `${Object.entries(estimate.node.gasEstimate).map(([key, value]) => `${friendlyNames[key]}: ${value} gas`).join(' ')}`, + }, + ], } - await this.plugin.call('editor', 'discardLineTexts') - if (gasEstimates) { - for (const estimate of gasEstimates) { - const linetext: lineText = { - content: Object.entries(estimate.node.gasEstimate).map(([, value]) => `${value} gas`).join(' '), - position: estimate.range, - hide: false, - className: 'text-muted small', - afterContentClassName: 'text-muted small fas fa-gas-pump pl-4', - from: 'codeParser', - hoverMessage: [{ - value: `${Object.entries(estimate.node.gasEstimate).map(([key, value]) => `${friendlyNames[key]}: ${value} gas`).join(' ')}`, - }, - ], - } - this.plugin.call('editor', 'addLineText', linetext, estimate.range.fileName) + this.plugin.call('editor', 'addLineText', linetext, estimate.range.fileName) - } - } + } } + } } \ No newline at end of file diff --git a/apps/remix-ide/src/app/plugins/parser/services/code-parser-imports.ts b/apps/remix-ide/src/app/plugins/parser/services/code-parser-imports.ts index 1af4591ba1..8e216958a1 100644 --- a/apps/remix-ide/src/app/plugins/parser/services/code-parser-imports.ts +++ b/apps/remix-ide/src/app/plugins/parser/services/code-parser-imports.ts @@ -9,96 +9,87 @@ export type CodeParserImportsData = { } export default class CodeParserImports { - plugin: CodeParser - - data: CodeParserImportsData = {} - constructor(plugin: CodeParser) { - this.plugin = plugin - this.init() - } - - async getImports() { - return this.data + plugin: CodeParser + + data: CodeParserImportsData = {} + constructor(plugin: CodeParser) { + this.plugin = plugin + this.init() + } + + async getImports(){ + return this.data + } + + async init() { + // @ts-ignore + const txt = await import('raw-loader!libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt') + this.data.modules = txt.default.split('\n') + .filter(x => x !== '') + .map(x => x.replace('./node_modules/', '')) + .filter(x => { + if(x.includes('@openzeppelin')) { + return !x.includes('mock') + }else{ + return true + } + }) + + // get unique first words of the values in the array + this.data.packages = [...new Set(this.data.modules.map(x => x.split('/')[0]))] + } + + setFileTree = async () => { + if (isElectron()) { + const files = await this.plugin.call('fs', 'glob', '/', '**/*.sol') + // only get path property of files + this.data.files = files.map((x) => x.path) + } else { + this.data.files = await this.getDirectory('/') + this.data.files = this.data.files.filter((x) => x.endsWith('.sol') && !x.startsWith('.deps') && !x.startsWith('.git')) } - - async init() { - // @ts-ignore - const txt = await import('raw-loader!libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt') - this.data.modules = txt.default.split('\n') - .filter(x => x !== '') - .map(x => x.replace('./node_modules/', '')) - .filter(x => { - if (x.includes('@openzeppelin')) { - return !x.includes('mock') - } else { - return true - } - }) - // get unique first words of the values in the array - this.data.packages = [...new Set(this.data.modules.map(x => x.split('/')[0]))] - } - - setFileTree = async () => { - - if (isElectron()) { - const files = await this.plugin.call('fs', 'glob', '/', '**/*.sol') - // only get path property of files - this.data.files = files.map(x => x.path) - + } + + getDirectory = async (dir: string) => { + let result = [] + let files = {} + try { + if (await this.plugin.call('fileManager', 'exists', dir)) { + files = await this.plugin.call('fileManager', 'readdir', dir) + } + } catch (e) {} + + const fileArray = this.normalize(files) + for (const fi of fileArray) { + if (fi) { + const type = fi.data.isDirectory + if (type === true) { + result = [...result, ...(await this.getDirectory(`${fi.filename}`))] } else { - - this.data.files = await this.getDirectory('/') - this.data.files = this.data.files.filter(x => x.endsWith('.sol') && !x.startsWith('.deps') && !x.startsWith('.git')) - - + result = [...result, fi.filename] } + } } - - getDirectory = async (dir: string) => { - - console.log('getDirectorySEARCH', dir) - let result = [] - - let files = {} - try { - if (await this.plugin.call('fileManager', 'exists', dir)) { - files = await this.plugin.call('fileManager', 'readdir', dir) - } - } catch (e) { } - - const fileArray = this.normalize(files) - for (const fi of fileArray) { - if (fi) { - const type = fi.data.isDirectory - if (type === true) { - result = [...result, ...(await this.getDirectory(`${fi.filename}`))] - } else { - result = [...result, fi.filename] - } - } - } - - return result - } - - normalize = filesList => { - console.log('normalize', filesList) - const folders = [] - const files = [] - Object.keys(filesList || {}).forEach(key => { - if (filesList[key].isDirectory) { - folders.push({ - filename: key, - data: filesList[key] - }) - } else { - files.push({ - filename: key, - data: filesList[key] - }) - } + return result + } + + normalize = filesList => { + const folders = [] + const files = [] + Object.keys(filesList || {}).forEach(key => { + if (filesList[key].isDirectory) { + folders.push({ + filename: key, + data: filesList[key] }) - return [...folders, ...files] - } + } else { + files.push({ + filename: key, + data: filesList[key] + }) + } + }) + return [...folders, ...files] + } } \ No newline at end of file diff --git a/apps/remix-ide/src/app/plugins/parser/types/antlr-types.ts b/apps/remix-ide/src/app/plugins/parser/types/antlr-types.ts index ebe8a8ea7d..3e2675c43a 100644 --- a/apps/remix-ide/src/app/plugins/parser/types/antlr-types.ts +++ b/apps/remix-ide/src/app/plugins/parser/types/antlr-types.ts @@ -596,132 +596,132 @@ type ASTTypeMap = ASTMap export const astNodeTypes = [ - 'SourceUnit', - 'PragmaDirective', - 'ImportDirective', - 'ContractDefinition', - 'InheritanceSpecifier', - 'StateVariableDeclaration', - 'UsingForDeclaration', - 'StructDefinition', - 'ModifierDefinition', - 'ModifierInvocation', - 'FunctionDefinition', - 'EventDefinition', - 'CustomErrorDefinition', - 'RevertStatement', - 'EnumValue', - 'EnumDefinition', - 'VariableDeclaration', - 'UserDefinedTypeName', - 'Mapping', - 'ArrayTypeName', - 'FunctionTypeName', - 'Block', - 'ExpressionStatement', - 'IfStatement', - 'WhileStatement', - 'ForStatement', - 'InlineAssemblyStatement', - 'DoWhileStatement', - 'ContinueStatement', - 'Break', - 'Continue', - 'BreakStatement', - 'ReturnStatement', - 'EmitStatement', - 'ThrowStatement', - 'VariableDeclarationStatement', - 'ElementaryTypeName', - 'FunctionCall', - 'AssemblyBlock', - 'AssemblyCall', - 'AssemblyLocalDefinition', - 'AssemblyAssignment', - 'AssemblyStackAssignment', - 'LabelDefinition', - 'AssemblySwitch', - 'AssemblyCase', - 'AssemblyFunctionDefinition', - 'AssemblyFunctionReturns', - 'AssemblyFor', - 'AssemblyIf', - 'SubAssembly', - 'TupleExpression', - 'NameValueExpression', - 'BooleanLiteral', - 'NumberLiteral', - 'Identifier', - 'BinaryOperation', - 'UnaryOperation', - 'NewExpression', - 'Conditional', - 'StringLiteral', - 'HexLiteral', - 'HexNumber', - 'DecimalNumber', - 'MemberAccess', - 'IndexAccess', - 'IndexRangeAccess', - 'NameValueList', - 'UncheckedStatement', - 'TryStatement', - 'CatchClause', - 'FileLevelConstant', - 'AssemblyMemberAccess', - 'TypeDefinition', - 'InvalidNode' + 'SourceUnit', + 'PragmaDirective', + 'ImportDirective', + 'ContractDefinition', + 'InheritanceSpecifier', + 'StateVariableDeclaration', + 'UsingForDeclaration', + 'StructDefinition', + 'ModifierDefinition', + 'ModifierInvocation', + 'FunctionDefinition', + 'EventDefinition', + 'CustomErrorDefinition', + 'RevertStatement', + 'EnumValue', + 'EnumDefinition', + 'VariableDeclaration', + 'UserDefinedTypeName', + 'Mapping', + 'ArrayTypeName', + 'FunctionTypeName', + 'Block', + 'ExpressionStatement', + 'IfStatement', + 'WhileStatement', + 'ForStatement', + 'InlineAssemblyStatement', + 'DoWhileStatement', + 'ContinueStatement', + 'Break', + 'Continue', + 'BreakStatement', + 'ReturnStatement', + 'EmitStatement', + 'ThrowStatement', + 'VariableDeclarationStatement', + 'ElementaryTypeName', + 'FunctionCall', + 'AssemblyBlock', + 'AssemblyCall', + 'AssemblyLocalDefinition', + 'AssemblyAssignment', + 'AssemblyStackAssignment', + 'LabelDefinition', + 'AssemblySwitch', + 'AssemblyCase', + 'AssemblyFunctionDefinition', + 'AssemblyFunctionReturns', + 'AssemblyFor', + 'AssemblyIf', + 'SubAssembly', + 'TupleExpression', + 'NameValueExpression', + 'BooleanLiteral', + 'NumberLiteral', + 'Identifier', + 'BinaryOperation', + 'UnaryOperation', + 'NewExpression', + 'Conditional', + 'StringLiteral', + 'HexLiteral', + 'HexNumber', + 'DecimalNumber', + 'MemberAccess', + 'IndexAccess', + 'IndexRangeAccess', + 'NameValueList', + 'UncheckedStatement', + 'TryStatement', + 'CatchClause', + 'FileLevelConstant', + 'AssemblyMemberAccess', + 'TypeDefinition', + 'InvalidNode' ] as const export const binaryOpValues = [ - '+', - '-', - '*', - '/', - '**', - '%', - '<<', - '>>', - '&&', - '||', - ',,', - '&', - ',', - '^', - '<', - '>', - '<=', - '>=', - '==', - '!=', - '=', - ',=', - '^=', - '&=', - '<<=', - '>>=', - '+=', - '-=', - '*=', - '/=', - '%=', - '|', - '|=', + '+', + '-', + '*', + '/', + '**', + '%', + '<<', + '>>', + '&&', + '||', + ',,', + '&', + ',', + '^', + '<', + '>', + '<=', + '>=', + '==', + '!=', + '=', + ',=', + '^=', + '&=', + '<<=', + '>>=', + '+=', + '-=', + '*=', + '/=', + '%=', + '|', + '|=', ] as const export type BinOp = typeof binaryOpValues[number] export const unaryOpValues = [ - '-', - '+', - '++', - '--', - '~', - 'after', - 'delete', - '!', + '-', + '+', + '++', + '--', + '~', + 'after', + 'delete', + '!', ] as const export type UnaryOp = typeof unaryOpValues[number] diff --git a/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx b/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx index f4dbf5d095..a77a210277 100644 --- a/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx +++ b/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx @@ -1,9 +1,9 @@ import React from 'react' // eslint-disable-line -import { FormattedMessage } from 'react-intl' -import { Plugin } from '@remixproject/engine' -import { AppModal } from '@remix-ui/app' -import { PermissionHandlerDialog, PermissionHandlerValue } from '@remix-ui/permission-handler' -import { Profile } from '@remixproject/plugin-utils' +import {FormattedMessage} from 'react-intl' +import {Plugin} from '@remixproject/engine' +import {AppModal} from '@remix-ui/app' +import {PermissionHandlerDialog, PermissionHandlerValue} from '@remix-ui/permission-handler' +import {Profile} from '@remixproject/plugin-utils' const profile = { name: 'permissionhandler', @@ -46,16 +46,12 @@ export class PermissionHandlerPlugin extends Plugin { } } - switchMode (from: Profile, to: Profile, method: string, set: boolean, sensitiveCall: boolean) { + switchMode(from: Profile, to: Profile, method: string, set: boolean, sensitiveCall: boolean) { if (sensitiveCall) { - set - ? this.sessionPermissions[to.name][method][from.name] = {} - : delete this.sessionPermissions[to.name][method][from.name] + set ? (this.sessionPermissions[to.name][method][from.name] = {}) : delete this.sessionPermissions[to.name][method][from.name] } else { - set - ? this.permissions[to.name][method][from.name] = {} - : delete this.permissions[to.name][method][from.name] - } + set ? (this.permissions[to.name][method][from.name] = {}) : delete this.permissions[to.name][method][from.name] + } } clear() { @@ -93,7 +89,7 @@ export class PermissionHandlerPlugin extends Plugin { if (!this.permissions[to.name][method][from.name]) return this.openPermission(from, to, method, message, sensitiveCall) } - const { allow, hash } = sensitiveCall ? this.sessionPermissions[to.name][method][from.name] : this.permissions[to.name][method][from.name] + const {allow, hash} = sensitiveCall ? this.sessionPermissions[to.name][method][from.name] : this.permissions[to.name][method][from.name] if (!allow) { const warning = this.notAllowWarning(from, to, method) this.call('notification', 'toast', warning) @@ -124,10 +120,10 @@ export class PermissionHandlerPlugin extends Plugin { } const modal: AppModal = { id: 'PermissionHandler', - title: , + title: , message: , - okLabel: , - cancelLabel: + okLabel: , + cancelLabel: } const result = await this.call('notification', 'modal', modal) @@ -166,7 +162,7 @@ export class PermissionHandlerPlugin extends Plugin { } this.persistPermissions() } - } + } reject(this.notAllowWarning(from, to, method)) } }) diff --git a/apps/remix-ide/src/app/plugins/remixd-handle.tsx b/apps/remix-ide/src/app/plugins/remixd-handle.tsx index f12c82519e..eb3d9242e4 100644 --- a/apps/remix-ide/src/app/plugins/remixd-handle.tsx +++ b/apps/remix-ide/src/app/plugins/remixd-handle.tsx @@ -1,12 +1,12 @@ /* eslint-disable no-unused-vars */ -import React, { useRef, useState, useEffect } from 'react' // eslint-disable-line +import React, {useRef, useState, useEffect} from 'react' // eslint-disable-line import isElectron from 'is-electron' -import { WebsocketPlugin } from '@remixproject/engine-web' +import {WebsocketPlugin} from '@remixproject/engine-web' import * as packageJson from '../../../../../package.json' // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries -import { version as remixdVersion } from '../../../../../libs/remixd/package.json' -import { PluginManager } from '@remixproject/engine' -import { AppModal, AlertModal } from '@remix-ui/app' +import {version as remixdVersion} from '../../../../../libs/remixd/package.json' +import {PluginManager} from '@remixproject/engine' +import {AppModal, AlertModal} from '@remix-ui/app' const LOCALHOST = ' - connect to localhost - ' @@ -19,10 +19,10 @@ const profile = { description: 'Using Remixd daemon, allow to access file system', kind: 'other', version: packageJson.version, - repo: "https://github.com/ethereum/remix-project/tree/master/libs/remixd", - maintainedBy: "Remix", - documentation: "https://remix-ide.readthedocs.io/en/latest/remixd.html", - authorContact: "" + repo: 'https://github.com/ethereum/remix-project/tree/master/libs/remixd', + maintainedBy: 'Remix', + documentation: 'https://remix-ide.readthedocs.io/en/latest/remixd.html', + authorContact: '' } export class RemixdHandle extends WebsocketPlugin { @@ -63,7 +63,6 @@ export class RemixdHandle extends WebsocketPlugin { } await this.appManager.deactivatePlugin('remixd') - } async callPluginMethod(key: string, payload?: any[]) { @@ -75,11 +74,11 @@ export class RemixdHandle extends WebsocketPlugin { } /** - * connect to localhost if no connection and render the explorer - * disconnect from localhost if connected and remove the explorer - * - * @param {String} txHash - hash of the transaction - */ + * connect to localhost if no connection and render the explorer + * disconnect from localhost if connected and remove the explorer + * + * @param {String} txHash - hash of the transaction + */ async connectToLocalhost() { const connection = async (error?: any) => { if (error) { @@ -92,7 +91,8 @@ export class RemixdHandle extends WebsocketPlugin { this.canceled() } else { const intervalId = setInterval(() => { - if (!this.socket || (this.socket && this.socket.readyState === 3)) { // 3 means connection closed + if (!this.socket || (this.socket && this.socket.readyState === 3)) { + // 3 means connection closed clearInterval(intervalId) const alert: AlertModal = { id: 'connectionAlert', @@ -103,8 +103,8 @@ export class RemixdHandle extends WebsocketPlugin { } }, 3000) this.localhostProvider.init(() => { - this.call('filePanel', 'setWorkspace', { name: LOCALHOST, isLocalhost: true }, true) - }); + this.call('filePanel', 'setWorkspace', {name: LOCALHOST, isLocalhost: true}, true) + }) for (const plugin of this.dependentPlugins) { await this.appManager.activatePlugin(plugin) } @@ -119,7 +119,7 @@ export class RemixdHandle extends WebsocketPlugin { title: 'Access file system using remixd', message: remixdDialog(), okLabel: 'Connect', - cancelLabel: 'Cancel', + cancelLabel: 'Cancel' } const result = await this.call('notification', 'modal', mod) if (result) { @@ -127,7 +127,8 @@ export class RemixdHandle extends WebsocketPlugin { this.localhostProvider.preInit() super.activate() setTimeout(() => { - if (!this.socket || (this.socket && this.socket.readyState === 3)) { // 3 means connection closed + if (!this.socket || (this.socket && this.socket.readyState === 3)) { + // 3 means connection closed connection(new Error('Connection with daemon failed.')) } else { connection() @@ -136,14 +137,15 @@ export class RemixdHandle extends WebsocketPlugin { } catch (error) { connection(error) } - } - else { + } else { await this.canceled() } } else { try { super.activate() - setTimeout(() => { connection() }, 2000) + setTimeout(() => { + connection() + }, 2000) } catch (error) { connection(error) } @@ -154,37 +156,53 @@ export class RemixdHandle extends WebsocketPlugin { function remixdDialog() { const commandText = 'remixd' const fullCommandText = 'remixd -s -u ' - return (<> -
-
- Access your local file system from Remix IDE using Remixd NPM package. -
-
- Remixd documentation. -
-
- The remixd command is: -
{commandText} -
-
- The remixd command without options uses the terminal's current directory as the shared directory and the shared Remix domain can only be https://remix.ethereum.org, https://remix-alpha.ethereum.org, or https://remix-beta.ethereum.org -
-
- Example command with flags:
- {fullCommandText} -
-
- For info about ports, see Remixd ports usage -
-
- This feature is still in Alpha. We recommend to keep a backup of the shared folder. -
-
-
- Before using, make sure remixd version is latest i.e. v{remixdVersion} -

Read here how to update it -
+ return ( + <> +
+
+ Access your local file system from Remix IDE using{' '} + + Remixd NPM package + + . +
+
+ Remixd{' '} + + documentation + + . +
+
+ The remixd command is: +
+ {commandText} +
+
+ The remixd command without options uses the terminal's current directory as the shared directory and the shared Remix domain can only be https://remix.ethereum.org, + https://remix-alpha.ethereum.org, or https://remix-beta.ethereum.org +
+
+ Example command with flags:
+ {fullCommandText} +
+
+ For info about ports, see{' '} + + Remixd ports usage + +
+
This feature is still in Alpha. We recommend to keep a backup of the shared folder.
+
+
+ Before using, make sure remixd version is latest i.e. v{remixdVersion} +

+ + Read here how to update it + +
+
-
- ) + + ) } diff --git a/apps/remix-ide/src/app/plugins/solidity-script.tsx b/apps/remix-ide/src/app/plugins/solidity-script.tsx index bf0be9ad53..a19ca834df 100644 --- a/apps/remix-ide/src/app/plugins/solidity-script.tsx +++ b/apps/remix-ide/src/app/plugins/solidity-script.tsx @@ -1,9 +1,9 @@ import React from 'react' // eslint-disable-line -import { format } from 'util' -import { Plugin } from '@remixproject/engine' -import { compile } from '@remix-project/remix-solidity' -import { TransactionConfig } from 'web3-core' -const _paq = window._paq = window._paq || [] //eslint-disable-line +import {format} from 'util' +import {Plugin} from '@remixproject/engine' +import {compile} from '@remix-project/remix-solidity' +import {TransactionConfig} from 'web3-core' +const _paq = (window._paq = window._paq || []) //eslint-disable-line const profile = { name: 'solidity-script', @@ -13,17 +13,16 @@ const profile = { } export class SolidityScript extends Plugin { - constructor () { + constructor() { super(profile) } - async execute (path: string, functionName: string = 'run') { + async execute(path: string, functionName: string = 'run') { _paq.push(['trackEvent', 'SolidityScript', 'execute', 'script']) this.call('terminal', 'log', `Running free function '${functionName}' from ${path}...`) let content = await this.call('fileManager', 'readFile', path) const params = await this.call('solidity', 'getCompilerParameters') - content = ` // SPDX-License-Identifier: GPL-3.0 @@ -38,13 +37,15 @@ export class SolidityScript extends Plugin { ${functionName}(); } }` - const targets = { 'script.sol': { content } } + const targets = {'script.sol': {content}} // compile const compilation = await compile(targets, params, async (url, cb) => { - await this.call('contentImport', 'resolveAndSave', url).then((result) => cb(null, result)).catch((error) => cb(error.message)) + await this.call('contentImport', 'resolveAndSave', url) + .then((result) => cb(null, result)) + .catch((error) => cb(error.message)) }) - + if (compilation.data.error) { this.call('terminal', 'log', compilation.data.error.formattedMessage) } @@ -53,7 +54,7 @@ export class SolidityScript extends Plugin { this.call('terminal', 'log', error.formattedMessage) }) } - + // get the contract const contract = compilation.getContract('SolidityScript') if (!contract) { @@ -83,24 +84,28 @@ export class SolidityScript extends Plugin { const hhlogs = await web3.eth.getHHLogsForTx(receiptCall.transactionHash) if (hhlogs && hhlogs.length) { - const finalLogs =
console.log:
- { - hhlogs.map((log) => { - let formattedLog - // Hardhat implements the same formatting options that can be found in Node.js' console.log, - // which in turn uses util.format: https://nodejs.org/dist/latest-v12.x/docs/api/util.html#util_util_format_format_args - // For example: console.log("Name: %s, Age: %d", remix, 6) will log 'Name: remix, Age: 6' - // We check first arg to determine if 'util.format' is needed - if (typeof log[0] === 'string' && (log[0].includes('%s') || log[0].includes('%d'))) { - formattedLog = format(log[0], ...log.slice(1)) - } else { - formattedLog = log.join(' ') - } - return
{formattedLog}
- })} -
+ const finalLogs = ( +
+
+ console.log: +
+ {hhlogs.map((log) => { + let formattedLog + // Hardhat implements the same formatting options that can be found in Node.js' console.log, + // which in turn uses util.format: https://nodejs.org/dist/latest-v12.x/docs/api/util.html#util_util_format_format_args + // For example: console.log("Name: %s, Age: %d", remix, 6) will log 'Name: remix, Age: 6' + // We check first arg to determine if 'util.format' is needed + if (typeof log[0] === 'string' && (log[0].includes('%s') || log[0].includes('%d'))) { + formattedLog = format(log[0], ...log.slice(1)) + } else { + formattedLog = log.join(' ') + } + return
{formattedLog}
+ })} +
+ ) _paq.push(['trackEvent', 'udapp', 'hardhat', 'console.log']) this.call('terminal', 'logHtml', finalLogs) } - } + } } diff --git a/apps/remix-ide/src/app/plugins/solidity-umlgen.tsx b/apps/remix-ide/src/app/plugins/solidity-umlgen.tsx index 5abacd0409..ebbb7b9bb2 100644 --- a/apps/remix-ide/src/app/plugins/solidity-umlgen.tsx +++ b/apps/remix-ide/src/app/plugins/solidity-umlgen.tsx @@ -1,56 +1,29 @@ /* eslint-disable @nrwl/nx/enforce-module-boundaries */ -import { ViewPlugin } from '@remixproject/engine-web' +import {ViewPlugin} from '@remixproject/engine-web' import React from 'react' // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries -import { RemixUiSolidityUmlGen } from '@remix-ui/solidity-uml-gen' -import { ISolidityUmlGen, ThemeQualityType, ThemeSummary } from 'libs/remix-ui/solidity-uml-gen/src/types' -import { RemixAppManager } from 'libs/remix-ui/plugin-manager/src/types' -import { normalizeContractPath } from 'libs/remix-ui/solidity-compiler/src/lib/logic/flattenerUtilities' -import { convertAST2UmlClasses } from 'sol2uml/lib/converterAST2Classes' +import {RemixUiSolidityUmlGen} from '@remix-ui/solidity-uml-gen' +import {ISolidityUmlGen, ThemeQualityType, ThemeSummary} from 'libs/remix-ui/solidity-uml-gen/src/types' +import {RemixAppManager} from 'libs/remix-ui/plugin-manager/src/types' +import {normalizeContractPath} from 'libs/remix-ui/solidity-compiler/src/lib/logic/flattenerUtilities' +import {convertAST2UmlClasses} from 'sol2uml/lib/converterAST2Classes' import vizRenderStringSync from '@aduh95/viz.js/sync' -import { PluginViewWrapper } from '@remix-ui/helper' -import { customAction } from '@remixproject/plugin-api' -import { ClassOptions } from 'sol2uml/lib/converterClass2Dot' +import {PluginViewWrapper} from '@remix-ui/helper' +import {customAction} from '@remixproject/plugin-api' +import {ClassOptions} from 'sol2uml/lib/converterClass2Dot' const parser = (window as any).SolidityParser -const _paq = window._paq = window._paq || [] +const _paq = (window._paq = window._paq || []) const profile = { - name: 'solidityumlgen', - displayName: 'Solidity UML Generator', - description: 'Generates UML diagram in svg format from last compiled contract', - location: 'mainPanel', - methods: ['showUmlDiagram', 'generateUml', 'generateCustomAction'], - events: [], + name: 'solidityumlgen', + displayName: 'Solidity UML Generator', + description: 'Generates UML diagram in svg format from last compiled contract', + location: 'mainPanel', + methods: ['showUmlDiagram', 'generateUml', 'generateCustomAction'], + events: [] } -const themeCollection = [ - { themeName: 'HackerOwl', backgroundColor: '#011628', textColor: '#babbcc', - shapeColor: '#8694a1',fillColor: '#011C32'}, - { themeName: 'Cerulean', backgroundColor: '#ffffff', textColor: '#343a40', - shapeColor: '#343a40',fillColor: '#f8f9fa'}, - { themeName: 'Cyborg', backgroundColor: '#060606', textColor: '#adafae', - shapeColor: '#adafae', fillColor: '#222222'}, - { themeName: 'Dark', backgroundColor: '#222336', textColor: '#babbcc', - shapeColor: '#babbcc',fillColor: '#2a2c3f'}, - { themeName: 'Flatly', backgroundColor: '#ffffff', textColor: '#343a40', - shapeColor: '#7b8a8b',fillColor: '#ffffff'}, - { themeName: 'Black', backgroundColor: '#1a1a1a', textColor: '#babbcc', - shapeColor: '#b5b4bc',fillColor: '#1f2020'}, - { themeName: 'Light', backgroundColor: '#eef1f6', textColor: '#3b445e', - shapeColor: '#343a40',fillColor: '#ffffff'}, - { themeName: 'Midcentury', backgroundColor: '#DBE2E0', textColor: '#11556c', - shapeColor: '#343a40',fillColor: '#eeede9'}, - { themeName: 'Spacelab', backgroundColor: '#ffffff', textColor: '#343a40', - shapeColor: '#333333', fillColor: '#eeeeee'}, - { themeName: 'Candy', backgroundColor: '#d5efff', textColor: '#11556c', - shapeColor: '#343a40',fillColor: '#fbe7f8' }, - { themeName: 'Violet', backgroundColor: '#f1eef6', textColor: '#3b445e', - shapeColor: '#343a40',fillColor: '#f8fafe' }, - { themeName: 'Unicorn', backgroundColor: '#f1eef6', textColor: '#343a40', - shapeColor: '#343a40',fillColor: '#f8fafe' }, -] - /** * add context menu which will offer download as pdf and download png. * add menu under the first download button to download @@ -81,8 +54,7 @@ export class SolidityUmlGen extends ViewPlugin implements ISolidityUmlGen { this.currentlySelectedTheme = '' this.themeName = '' - this.themeCollection = themeCollection - this.activeTheme = themeCollection.find(t => t.themeName === 'Dark') + this.activeTheme = {} as ThemeSummary this.appManager = appManager this.element = document.createElement('div') this.element.setAttribute('id', 'sol-uml-gen') @@ -91,7 +63,7 @@ export class SolidityUmlGen extends ViewPlugin implements ISolidityUmlGen { onActivation(): void { this.handleThemeChange() this.on('solidity', 'compilationFinished', async (file: string, source, languageVersion, data, input, version) => { - if(!this.triggerGenerateUml) return + if (!this.triggerGenerateUml) return this.triggerGenerateUml = false const currentTheme: ThemeQualityType = await this.call('theme', 'currentTheme') this.currentlySelectedTheme = currentTheme.quality @@ -100,14 +72,20 @@ export class SolidityUmlGen extends ViewPlugin implements ISolidityUmlGen { const normalized = normalizeContractPath(file) this.currentFile = normalized[normalized.length - 1] try { - if (data.sources && Object.keys(data.sources).length > 1) { // we should flatten first as there are multiple asts + if (data.sources && Object.keys(data.sources).length > 1) { + // we should flatten first as there are multiple asts result = await this.flattenContract(source, file, data) } const ast = result.length > 1 ? parser.parse(result) : parser.parse(source.sources[file].content) this.umlClasses = convertAST2UmlClasses(ast, this.currentFile) let umlDot = '' - this.activeTheme = themeCollection.find(theme => theme.themeName === currentTheme.name) - umlDot = convertUmlClasses2Dot(this.umlClasses, false, { backColor: this.activeTheme.backgroundColor, textColor: this.activeTheme.textColor, shapeColor: this.activeTheme.shapeColor, fillColor: this.activeTheme.fillColor }) + this.activeTheme = await this.call('theme', 'currentTheme') + umlDot = convertUmlClasses2Dot(this.umlClasses, false, { + backColor: this.activeTheme.backgroundColor, + textColor: this.activeTheme.textColor, + shapeColor: this.activeTheme.shapeColor, + fillColor: this.activeTheme.fillColor + }) const payload = vizRenderStringSync(umlDot) this.updatedSvg = payload _paq.push(['trackEvent', 'solidityumlgen', 'umlgenerated']) @@ -120,42 +98,26 @@ export class SolidityUmlGen extends ViewPlugin implements ISolidityUmlGen { } getThemeCssVariables(cssVars: string) { - return window.getComputedStyle(document.documentElement) - .getPropertyValue(cssVars) + return window.getComputedStyle(document.documentElement).getPropertyValue(cssVars) } private handleThemeChange() { this.on('theme', 'themeChanged', async (theme) => { this.currentlySelectedTheme = theme.quality - const themeQuality: ThemeQualityType = await this.call('theme', 'currentTheme') - themeCollection.forEach((theme) => { - if (theme.themeName === themeQuality.name) { - this.themeDark = theme.backgroundColor - this.activeTheme = theme - const umlDot = convertUmlClasses2Dot(this.umlClasses, false, { backColor: this.activeTheme.backgroundColor, textColor: this.activeTheme.textColor, shapeColor: this.activeTheme.shapeColor, fillColor: this.activeTheme.fillColor }) - this.updatedSvg = vizRenderStringSync(umlDot) - this.renderComponent() - } + this.activeTheme = theme + this.themeDark = theme.backgroundColor + const umlDot = convertUmlClasses2Dot(this.umlClasses, false, { + backColor: this.activeTheme.backgroundColor, + textColor: this.activeTheme.textColor, + shapeColor: this.activeTheme.shapeColor, + fillColor: this.activeTheme.fillColor }) + this.updatedSvg = vizRenderStringSync(umlDot) + this.renderComponent() await this.call('tabs', 'focus', 'solidityumlgen') }) } - async mangleSvgPayload(svgPayload: string) : Promise { - const parser = new DOMParser() - const themeQuality: ThemeQualityType = await this.call('theme', 'currentTheme') - const parsedDocument = parser.parseFromString(svgPayload, 'image/svg+xml') - const element = parsedDocument.getElementsByTagName('svg') - themeCollection.forEach((theme) => { - if (theme.themeName === themeQuality.name) { - parsedDocument.documentElement.setAttribute('style', `background-color: var(${this.getThemeCssVariables('--body-bg')})`) - element[0].setAttribute('fill', theme.backgroundColor) - } - }) - const stringifiedSvg = new XMLSerializer().serializeToString(parsedDocument) - return stringifiedSvg - } - onDeactivation(): void { this.off('solidity', 'compilationFinished') } @@ -180,13 +142,11 @@ export class SolidityUmlGen extends ViewPlugin implements ISolidityUmlGen { * and assigns to a local property * @returns {Promise} */ - async flattenContract (source: any, filePath: string, data: any) { + async flattenContract(source: any, filePath: string, data: any) { const result = await this.call('contractflattener', 'flattenContract', source, filePath, data) return result } - - async showUmlDiagram(svgPayload: string) { this.updatedSvg = svgPayload this.renderComponent() @@ -197,18 +157,20 @@ export class SolidityUmlGen extends ViewPlugin implements ISolidityUmlGen { this.renderComponent() } - setDispatch (dispatch: React.Dispatch) { + setDispatch(dispatch: React.Dispatch) { this.dispatch = dispatch this.renderComponent() } render() { - return
- -
+ return ( +
+ +
+ ) } - renderComponent () { + renderComponent() { this.dispatch({ ...this, updatedSvg: this.updatedSvg, @@ -218,24 +180,25 @@ export class SolidityUmlGen extends ViewPlugin implements ISolidityUmlGen { themeDark: this.themeDark, fileName: this.currentFile, themeCollection: this.themeCollection, - activeTheme: this.activeTheme, + activeTheme: this.activeTheme }) } updateComponent(state: any) { - return + return ( + + ) } } - interface Sol2umlClassOptions extends ClassOptions { backColor?: string shapeColor?: string @@ -243,15 +206,10 @@ interface Sol2umlClassOptions extends ClassOptions { textColor?: string } -import { dirname } from 'path' -import { convertClass2Dot } from 'sol2uml/lib/converterClass2Dot' -import { - Association, - ClassStereotype, - ReferenceType, - UmlClass, -} from 'sol2uml/lib/umlClass' -import { findAssociatedClass } from 'sol2uml/lib/associations' +import {dirname} from 'path' +import {convertClass2Dot} from 'sol2uml/lib/converterClass2Dot' +import {Association, ClassStereotype, ReferenceType, UmlClass} from 'sol2uml/lib/umlClass' +import {findAssociatedClass} from 'sol2uml/lib/associations' // const debug = require('debug')('sol2uml') @@ -263,12 +221,8 @@ import { findAssociatedClass } from 'sol2uml/lib/associations' * @param classOptions command line options for the `class` command * @return dotString Graphviz's DOT format for defining nodes, edges and clusters. */ -export function convertUmlClasses2Dot( - umlClasses: UmlClass[], - clusterFolders: boolean = false, - classOptions: Sol2umlClassOptions = {} -): string { - let dotString: string = ` +export function convertUmlClasses2Dot(umlClasses: UmlClass[], clusterFolders: boolean = false, classOptions: Sol2umlClassOptions = {}): string { + let dotString: string = ` digraph UmlClassDiagram { rankdir=BT arrowhead=open @@ -276,160 +230,130 @@ bgcolor="${classOptions.backColor}" edge [color="${classOptions.shapeColor}"] node [shape=record, style=filled, color="${classOptions.shapeColor}", fillcolor="${classOptions.fillColor}", fontcolor="${classOptions.textColor}"]` - // Sort UML Classes by folder of source file - const umlClassesSortedByCodePath = sortUmlClassesByCodePath(umlClasses) + // Sort UML Classes by folder of source file + const umlClassesSortedByCodePath = sortUmlClassesByCodePath(umlClasses) - let currentCodeFolder = '' - for (const umlClass of umlClassesSortedByCodePath) { - const codeFolder = dirname(umlClass.relativePath) - if (currentCodeFolder !== codeFolder) { - // Need to close off the last subgraph if not the first - if (currentCodeFolder != '') { - dotString += '\n}' - } + let currentCodeFolder = '' + for (const umlClass of umlClassesSortedByCodePath) { + const codeFolder = dirname(umlClass.relativePath) + if (currentCodeFolder !== codeFolder) { + // Need to close off the last subgraph if not the first + if (currentCodeFolder != '') { + dotString += '\n}' + } - dotString += ` + dotString += ` subgraph ${getSubGraphName(clusterFolders)} { label="${codeFolder}"` - currentCodeFolder = codeFolder - } - dotString += convertClass2Dot(umlClass, classOptions) + currentCodeFolder = codeFolder } + dotString += convertClass2Dot(umlClass, classOptions) + } - // Need to close off the last subgraph if not the first - if (currentCodeFolder != '') { - dotString += '\n}' - } + // Need to close off the last subgraph if not the first + if (currentCodeFolder != '') { + dotString += '\n}' + } - dotString += addAssociationsToDot(umlClasses, classOptions) + dotString += addAssociationsToDot(umlClasses, classOptions) - // Need to close off the last the digraph - dotString += '\n}' + // Need to close off the last the digraph + dotString += '\n}' - // debug(dotString) + // debug(dotString) - return dotString + return dotString } let subGraphCount = 0 function getSubGraphName(clusterFolders: boolean = false) { - if (clusterFolders) { - return ` cluster_${subGraphCount++}` - } - return ` graph_${subGraphCount++}` + if (clusterFolders) { + return ` cluster_${subGraphCount++}` + } + return ` graph_${subGraphCount++}` } function sortUmlClassesByCodePath(umlClasses: UmlClass[]): UmlClass[] { - return umlClasses.sort((a, b) => { - if (a.relativePath < b.relativePath) { - return -1 - } - if (a.relativePath > b.relativePath) { - return 1 - } - return 0 - }) + return umlClasses.sort((a, b) => { + if (a.relativePath < b.relativePath) { + return -1 + } + if (a.relativePath > b.relativePath) { + return 1 + } + return 0 + }) } -export function addAssociationsToDot( - umlClasses: UmlClass[], - classOptions: ClassOptions = {} -): string { - let dotString: string = '' - - // for each class - for (const sourceUmlClass of umlClasses) { - if (!classOptions.hideEnums) { - // for each enum in the class - sourceUmlClass.enums.forEach((enumId) => { - // Has the enum been filtered out? eg depth limited - const targetUmlClass = umlClasses.find((c) => c.id === enumId) - if (targetUmlClass) { - // Draw aggregated link from contract to contract level Enum - dotString += `\n${enumId} -> ${sourceUmlClass.id} [arrowhead=diamond, weight=2]` - } - }) +export function addAssociationsToDot(umlClasses: UmlClass[], classOptions: ClassOptions = {}): string { + let dotString: string = '' + + // for each class + for (const sourceUmlClass of umlClasses) { + if (!classOptions.hideEnums) { + // for each enum in the class + sourceUmlClass.enums.forEach((enumId) => { + // Has the enum been filtered out? eg depth limited + const targetUmlClass = umlClasses.find((c) => c.id === enumId) + if (targetUmlClass) { + // Draw aggregated link from contract to contract level Enum + dotString += `\n${enumId} -> ${sourceUmlClass.id} [arrowhead=diamond, weight=2]` } - if (!classOptions.hideStructs) { - // for each struct in the class - sourceUmlClass.structs.forEach((structId) => { - // Has the struct been filtered out? eg depth limited - const targetUmlClass = umlClasses.find((c) => c.id === structId) - if (targetUmlClass) { - // Draw aggregated link from contract to contract level Struct - dotString += `\n${structId} -> ${sourceUmlClass.id} [arrowhead=diamond, weight=2]` - } - }) + }) + } + if (!classOptions.hideStructs) { + // for each struct in the class + sourceUmlClass.structs.forEach((structId) => { + // Has the struct been filtered out? eg depth limited + const targetUmlClass = umlClasses.find((c) => c.id === structId) + if (targetUmlClass) { + // Draw aggregated link from contract to contract level Struct + dotString += `\n${structId} -> ${sourceUmlClass.id} [arrowhead=diamond, weight=2]` } + }) + } - // for each association in that class - for (const association of Object.values(sourceUmlClass.associations)) { - const targetUmlClass = findAssociatedClass( - association, - sourceUmlClass, - umlClasses - ) - if (targetUmlClass) { - dotString += addAssociationToDot( - sourceUmlClass, - targetUmlClass, - association, - classOptions - ) - } - } + // for each association in that class + for (const association of Object.values(sourceUmlClass.associations)) { + const targetUmlClass = findAssociatedClass(association, sourceUmlClass, umlClasses) + if (targetUmlClass) { + dotString += addAssociationToDot(sourceUmlClass, targetUmlClass, association, classOptions) + } } + } - return dotString + return dotString } -function addAssociationToDot( - sourceUmlClass: UmlClass, - targetUmlClass: UmlClass, - association: Association, - classOptions: ClassOptions = {} -): string { - // do not include library or interface associations if hidden - // Or associations to Structs, Enums or Constants if they are hidden - if ( - (classOptions.hideLibraries && - (sourceUmlClass.stereotype === ClassStereotype.Library || - targetUmlClass.stereotype === ClassStereotype.Library)) || - (classOptions.hideInterfaces && - (targetUmlClass.stereotype === ClassStereotype.Interface || - sourceUmlClass.stereotype === ClassStereotype.Interface)) || - (classOptions.hideAbstracts && - (targetUmlClass.stereotype === ClassStereotype.Abstract || - sourceUmlClass.stereotype === ClassStereotype.Abstract)) || - (classOptions.hideStructs && - targetUmlClass.stereotype === ClassStereotype.Struct) || - (classOptions.hideEnums && - targetUmlClass.stereotype === ClassStereotype.Enum) || - (classOptions.hideConstants && - targetUmlClass.stereotype === ClassStereotype.Constant) - ) { - return '' - } +function addAssociationToDot(sourceUmlClass: UmlClass, targetUmlClass: UmlClass, association: Association, classOptions: ClassOptions = {}): string { + // do not include library or interface associations if hidden + // Or associations to Structs, Enums or Constants if they are hidden + if ( + (classOptions.hideLibraries && (sourceUmlClass.stereotype === ClassStereotype.Library || targetUmlClass.stereotype === ClassStereotype.Library)) || + (classOptions.hideInterfaces && (targetUmlClass.stereotype === ClassStereotype.Interface || sourceUmlClass.stereotype === ClassStereotype.Interface)) || + (classOptions.hideAbstracts && (targetUmlClass.stereotype === ClassStereotype.Abstract || sourceUmlClass.stereotype === ClassStereotype.Abstract)) || + (classOptions.hideStructs && targetUmlClass.stereotype === ClassStereotype.Struct) || + (classOptions.hideEnums && targetUmlClass.stereotype === ClassStereotype.Enum) || + (classOptions.hideConstants && targetUmlClass.stereotype === ClassStereotype.Constant) + ) { + return '' + } - let dotString = `\n${sourceUmlClass.id} -> ${targetUmlClass.id} [` + let dotString = `\n${sourceUmlClass.id} -> ${targetUmlClass.id} [` - if ( - association.referenceType == ReferenceType.Memory || - (association.realization && - targetUmlClass.stereotype === ClassStereotype.Interface) - ) { - dotString += 'style=dashed, ' - } + if (association.referenceType == ReferenceType.Memory || (association.realization && targetUmlClass.stereotype === ClassStereotype.Interface)) { + dotString += 'style=dashed, ' + } - if (association.realization) { - dotString += 'arrowhead=empty, arrowsize=3, ' - if (!targetUmlClass.stereotype) { - dotString += 'weight=4, ' - } else { - dotString += 'weight=3, ' - } + if (association.realization) { + dotString += 'arrowhead=empty, arrowsize=3, ' + if (!targetUmlClass.stereotype) { + dotString += 'weight=4, ' + } else { + dotString += 'weight=3, ' } + } - return dotString + ']' + return dotString + ']' } diff --git a/apps/remix-ide/src/app/providers/abstract-provider.tsx b/apps/remix-ide/src/app/providers/abstract-provider.tsx index 5d9df384c3..a5185b6129 100644 --- a/apps/remix-ide/src/app/providers/abstract-provider.tsx +++ b/apps/remix-ide/src/app/providers/abstract-provider.tsx @@ -1,30 +1,31 @@ -import { Plugin } from '@remixproject/engine' -import { AppModal, AlertModal, ModalTypes } from '@remix-ui/app' -import { Blockchain } from '../../blockchain/blockchain' -import { ethers } from 'ethers' +import {Plugin} from '@remixproject/engine' +import {AppModal, AlertModal, ModalTypes} from '@remix-ui/app' +import {Blockchain} from '../../blockchain/blockchain' +import {ethers} from 'ethers' export type JsonDataRequest = { - id: number, + id: number jsonrpc: string // version - method: string, - params: Array, + method: string + params: Array } export type JsonDataResult = { - id: number, + id: number jsonrpc: string // version - result?: any, - error?: any, + result?: any + error?: any + errorData?: any } export type RejectRequest = (error: Error) => void export type SuccessRequest = (data: JsonDataResult) => void export interface IProvider { - options: { [id: string] : any } - init(): Promise<{ [id: string] : any }> + options: {[id: string]: any} + init(): Promise<{[id: string]: any}> body(): JSX.Element - sendAsync (data: JsonDataRequest): Promise + sendAsync(data: JsonDataRequest): Promise } export abstract class AbstractProvider extends Plugin implements IProvider { @@ -33,9 +34,9 @@ export abstract class AbstractProvider extends Plugin implements IProvider { defaultUrl: string connected: boolean nodeUrl: string - options: { [id: string] : any } = {} + options: {[id: string]: any} = {} - constructor (profile, blockchain, defaultUrl) { + constructor(profile, blockchain, defaultUrl) { super(profile) this.defaultUrl = defaultUrl this.provider = null @@ -46,11 +47,11 @@ export abstract class AbstractProvider extends Plugin implements IProvider { abstract body(): JSX.Element - onDeactivation () { + onDeactivation() { this.provider = null } - async init () { + async init() { this.nodeUrl = await ((): Promise => { return new Promise((resolve, reject) => { const modalContent: AppModal = { @@ -61,15 +62,15 @@ export abstract class AbstractProvider extends Plugin implements IProvider { okLabel: 'OK', cancelLabel: 'Cancel', validationFn: (value) => { - if (!value) return { valid: false, message: "value is empty" } + if (!value) return {valid: false, message: 'value is empty'} if (value.startsWith('https://') || value.startsWith('http://')) { - return { - valid: true, + return { + valid: true, message: '' } } else { return { - valid: false, + valid: false, message: 'the provided value should contain the protocol ( e.g starts with http:// or https:// )' } } @@ -94,7 +95,7 @@ export abstract class AbstractProvider extends Plugin implements IProvider { } } - sendAsync (data: JsonDataRequest): Promise { + sendAsync(data: JsonDataRequest): Promise { // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve, reject) => { if (!this.provider) return reject(new Error('provider node set')) @@ -102,7 +103,7 @@ export abstract class AbstractProvider extends Plugin implements IProvider { }) } - private async switchAway (showError) { + private async switchAway(showError) { if (!this.provider) return this.provider = null this.connected = false @@ -110,19 +111,19 @@ export abstract class AbstractProvider extends Plugin implements IProvider { const modalContent: AlertModal = { id: this.profile.name, title: this.profile.displayName, - message: `Error while connecting to the provider, provider not connected`, + message: `Error while connecting to the provider, provider not connected` } this.call('notification', 'alert', modalContent) } - await this.call('udapp', 'setEnvironmentMode', { context: 'vm-merge'}) + await this.call('udapp', 'setEnvironmentMode', {context: 'vm-merge'}) return } - private async sendAsyncInternal (data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise { + private async sendAsyncInternal(data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise { if (this.provider) { try { const result = await this.provider.send(data.method, data.params) - resolve({ jsonrpc: '2.0', result, id: data.id }) + resolve({jsonrpc: '2.0', result, id: data.id}) } catch (error) { if (error && error.message && error.message.includes('net_version') && error.message.includes('SERVER_ERROR')) { this.switchAway(true) @@ -131,7 +132,7 @@ export abstract class AbstractProvider extends Plugin implements IProvider { } } else { const result = data.method === 'net_listening' ? 'canceled' : [] - resolve({ jsonrpc: '2.0', result: result, id: data.id }) + resolve({jsonrpc: '2.0', result: result, id: data.id}) } } } diff --git a/apps/remix-ide/src/app/providers/custom-vm-fork-provider.tsx b/apps/remix-ide/src/app/providers/custom-vm-fork-provider.tsx index c923560eb1..d25208bbb9 100644 --- a/apps/remix-ide/src/app/providers/custom-vm-fork-provider.tsx +++ b/apps/remix-ide/src/app/providers/custom-vm-fork-provider.tsx @@ -1,23 +1,27 @@ -import React, { useRef } from 'react' // eslint-disable-line +import React, {useRef} from 'react' // eslint-disable-line +import {FormattedMessage} from 'react-intl' import * as packageJson from '../../../../../package.json' -import { AppModal, ModalTypes } from '@remix-ui/app' -import { BasicVMProvider } from './vm-provider' -import { Hardfork } from '@ethereumjs/common' +import {AppModal, ModalTypes} from '@remix-ui/app' +import {BasicVMProvider} from './vm-provider' +import {Hardfork} from '@ethereumjs/common' export class CustomForkVMProvider extends BasicVMProvider { nodeUrl: string blockNumber: number | 'latest' inputs: any - constructor (blockchain) { - super({ - name: 'vm-custom-fork', - displayName: 'Custom fork - Remix VM', - kind: 'provider', - description: 'Custom fork - Remix VM', - methods: ['sendAsync', 'init'], - version: packageJson.version - }, blockchain) + constructor(blockchain) { + super( + { + name: 'vm-custom-fork', + displayName: 'Custom fork - Remix VM', + kind: 'provider', + description: 'Custom fork - Remix VM', + methods: ['sendAsync', 'init'], + version: packageJson.version + }, + blockchain + ) this.blockchain = blockchain this.fork = '' this.nodeUrl = '' @@ -25,28 +29,47 @@ export class CustomForkVMProvider extends BasicVMProvider { this.inputs = {} } - async init () { + async init() { const body = () => { - return
- Please provide information about the custom fork. If the node URL is not provided, the VM will start with an empty state. -
- - -
-
- - -
-
- - -
-
- } + return ( +
+ + + +
+ + +
+
+ + +
+
+ + +
+
+ ) + } const result = await ((): Promise => { return new Promise((resolve, reject) => { const modalContent: AppModal = { @@ -54,7 +77,7 @@ export class CustomForkVMProvider extends BasicVMProvider { title: this.profile.displayName, message: body(), validationFn: (data: any) => { - if(data.nodeUrl !== '' && !data.nodeUrl.startsWith("http")) { + if (data.nodeUrl !== '' && !data.nodeUrl.startsWith('http')) { return { valid: false, message: 'node URL should be a valid URL' @@ -96,11 +119,11 @@ export class CustomForkVMProvider extends BasicVMProvider { this.nodeUrl = undefined this.blockNumber = undefined } - + return { - 'fork': this.fork, - 'nodeUrl': this.nodeUrl, - 'blockNumber': this.blockNumber + fork: this.fork, + nodeUrl: this.nodeUrl, + blockNumber: this.blockNumber } } } diff --git a/apps/remix-ide/src/app/providers/external-http-provider.tsx b/apps/remix-ide/src/app/providers/external-http-provider.tsx index 36d864c2a1..f21d75d08f 100644 --- a/apps/remix-ide/src/app/providers/external-http-provider.tsx +++ b/apps/remix-ide/src/app/providers/external-http-provider.tsx @@ -1,6 +1,7 @@ import * as packageJson from '../../../../../package.json' import React from 'react' // eslint-disable-line -import { AbstractProvider } from './abstract-provider' +import {FormattedMessage} from 'react-intl' +import {AbstractProvider} from './abstract-provider' const profile = { name: 'basic-http-provider', @@ -12,25 +13,55 @@ const profile = { } export class ExternalHttpProvider extends AbstractProvider { - constructor (blockchain) { + constructor(blockchain) { super(profile, blockchain, 'http://127.0.0.1:8545') } - body (): JSX.Element { + body(): JSX.Element { const thePath = '' return ( <>
- Note: To use Geth & https://remix.ethereum.org, configure it to allow requests from Remix:(see Geth Docs on rpc server) + ( + + {chunks} + + ) + }} + />
geth --http --http.corsdomain https://remix.ethereum.org

- To run Remix & a local Geth test node, use this command: (see Geth Docs on Dev mode) -
geth --http --http.corsdomain="{window.origin}" --http.api web3,eth,debug,personal,net --vmdebug --datadir {thePath} --dev console
+ ( + + {chunks} + + ) + }} + /> +
+ geth --http --http.corsdomain="{window.origin}" --http.api web3,eth,debug,personal,net --vmdebug --datadir {thePath} --dev console +


- WARNING: It is not safe to use the --http.corsdomain flag with a wildcard: --http.corsdomain * + {chunks}}} />
-
For more info: Remix Docs on External HTTP Provider +
+ ( + + {chunks} + + ) + }} + />

External HTTP Provider Endpoint @@ -38,4 +69,4 @@ export class ExternalHttpProvider extends AbstractProvider { ) } -} \ No newline at end of file +} diff --git a/apps/remix-ide/src/app/providers/foundry-provider.tsx b/apps/remix-ide/src/app/providers/foundry-provider.tsx index 904c330b3c..47a3c2849f 100644 --- a/apps/remix-ide/src/app/providers/foundry-provider.tsx +++ b/apps/remix-ide/src/app/providers/foundry-provider.tsx @@ -1,6 +1,7 @@ import * as packageJson from '../../../../../package.json' import React from 'react' // eslint-disable-line -import { AbstractProvider } from './abstract-provider' +import {FormattedMessage} from 'react-intl' +import {AbstractProvider} from './abstract-provider' const profile = { name: 'foundry-provider', @@ -12,20 +13,35 @@ const profile = { } export class FoundryProvider extends AbstractProvider { - constructor (blockchain) { + constructor(blockchain) { super(profile, blockchain, 'http://127.0.0.1:8545') } - body (): JSX.Element { + body(): JSX.Element { return ( -
Note: To run Anvil on your system, run: -
curl -L https://foundry.paradigm.xyz | bash
-
anvil
+
+ {' '} + +
+ curl -L https://foundry.paradigm.xyz | bash +
+
+ anvil +
- For more info, visit: Foundry Documentation + ( + + {chunks} + + ) + }} + />
Anvil JSON-RPC Endpoint:
) } -} \ No newline at end of file +} diff --git a/apps/remix-ide/src/app/providers/ganache-provider.tsx b/apps/remix-ide/src/app/providers/ganache-provider.tsx index 132aa20957..79bac4b853 100644 --- a/apps/remix-ide/src/app/providers/ganache-provider.tsx +++ b/apps/remix-ide/src/app/providers/ganache-provider.tsx @@ -1,6 +1,7 @@ import * as packageJson from '../../../../../package.json' import React from 'react' // eslint-disable-line -import { AbstractProvider } from './abstract-provider' +import {FormattedMessage} from 'react-intl' +import {AbstractProvider} from './abstract-provider' const profile = { name: 'ganache-provider', @@ -12,20 +13,35 @@ const profile = { } export class GanacheProvider extends AbstractProvider { - constructor (blockchain) { + constructor(blockchain) { super(profile, blockchain, 'http://127.0.0.1:8545') } - body (): JSX.Element { + body(): JSX.Element { return ( -
Note: To run Ganache on your system, run: -
yarn global add ganache
-
ganache
+
+ {' '} + +
+ yarn global add ganache +
+
+ ganache +
- For more info, visit: Ganache Documentation + ( + + {chunks} + + ) + }} + />
Ganache JSON-RPC Endpoint:
) } -} \ No newline at end of file +} diff --git a/apps/remix-ide/src/app/providers/goerli-vm-fork-provider.tsx b/apps/remix-ide/src/app/providers/goerli-vm-fork-provider.tsx index 9327f38226..21f7845d33 100644 --- a/apps/remix-ide/src/app/providers/goerli-vm-fork-provider.tsx +++ b/apps/remix-ide/src/app/providers/goerli-vm-fork-provider.tsx @@ -1,29 +1,32 @@ import * as packageJson from '../../../../../package.json' -import { BasicVMProvider } from './vm-provider' +import {BasicVMProvider} from './vm-provider' export class GoerliForkVMProvider extends BasicVMProvider { nodeUrl: string blockNumber: number | 'latest' - constructor (blockchain) { - super({ - name: 'vm-goerli-fork', - displayName: 'Goerli fork - Remix VM (London)', - kind: 'provider', - description: 'Remix VM (London)', - methods: ['sendAsync', 'init'], - version: packageJson.version - }, blockchain) + constructor(blockchain) { + super( + { + name: 'vm-goerli-fork', + displayName: 'Goerli fork - Remix VM (London)', + kind: 'provider', + description: 'Remix VM (London)', + methods: ['sendAsync', 'init'], + version: packageJson.version + }, + blockchain + ) this.blockchain = blockchain this.fork = 'shanghai' this.nodeUrl = 'https://remix-sepolia.ethdevops.io' this.blockNumber = 'latest' } - async init () { + async init() { return { - 'fork': this.fork, - 'nodeUrl': this.nodeUrl, - 'blockNumber': this.blockNumber + fork: this.fork, + nodeUrl: this.nodeUrl, + blockNumber: this.blockNumber } } } diff --git a/apps/remix-ide/src/app/providers/hardhat-provider.tsx b/apps/remix-ide/src/app/providers/hardhat-provider.tsx index 1d579ab6c1..0dfe1c70af 100644 --- a/apps/remix-ide/src/app/providers/hardhat-provider.tsx +++ b/apps/remix-ide/src/app/providers/hardhat-provider.tsx @@ -1,6 +1,7 @@ import * as packageJson from '../../../../../package.json' import React from 'react' // eslint-disable-line -import { AbstractProvider } from './abstract-provider' +import {FormattedMessage} from 'react-intl' +import {AbstractProvider} from './abstract-provider' const profile = { name: 'hardhat-provider', @@ -12,19 +13,32 @@ const profile = { } export class HardhatProvider extends AbstractProvider { - constructor (blockchain) { + constructor(blockchain) { super(profile, blockchain, 'http://127.0.0.1:8545') } - body (): JSX.Element { + body(): JSX.Element { return ( -
Note: To run Hardhat network node on your system, go to hardhat project folder and run command: -
npx hardhat node
+
+ {' '} + +
+ npx hardhat node +
- For more info, visit: Hardhat Documentation + ( + + {chunks} + + ) + }} + />
Hardhat JSON-RPC Endpoint:
) } -} \ No newline at end of file +} diff --git a/apps/remix-ide/src/app/providers/injected-L2-provider.tsx b/apps/remix-ide/src/app/providers/injected-L2-provider.tsx deleted file mode 100644 index afae690a39..0000000000 --- a/apps/remix-ide/src/app/providers/injected-L2-provider.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { InjectedProviderDefaultBase } from './injected-provider-default' - -export class InjectedL2Provider extends InjectedProviderDefaultBase { - chainName: string - chainId: string - rpcUrls: Array - - constructor (profile: any, chainName: string, chainId: string, rpcUrls: Array) { - super(profile) - this.chainName = chainName - this.chainId = chainId - this.rpcUrls = rpcUrls - } - - async init () { - await super.init() - if (this.chainName && this.rpcUrls && this.rpcUrls.length > 0) await addL2Network(this.chainName, this.chainId, this.rpcUrls) - else - throw new Error('Cannot add the L2 network to main injected provider') - return {} - } -} - -export const addL2Network = async (chainName: string, chainId: string, rpcUrls: Array) => { - try { - await (window as any).ethereum.request({ - method: 'wallet_switchEthereumChain', - params: [{ chainId: chainId }], - }); - } catch (switchError) { - // This error code indicates that the chain has not been added to MetaMask. - if (switchError.code === 4902) { - try { - await (window as any).ethereum.request({ - method: 'wallet_addEthereumChain', - params: [ - { - chainId: chainId, - chainName: chainName, - rpcUrls: rpcUrls, - }, - ], - }); - - await (window as any).ethereum.request({ - method: 'wallet_switchEthereumChain', - params: [{ chainId: chainId }], - }); - } catch (addError) { - // handle "add" error - } - } - // handle other "switch" errors - } -} \ No newline at end of file diff --git a/apps/remix-ide/src/app/providers/injected-arbitrum-one-provider.tsx b/apps/remix-ide/src/app/providers/injected-arbitrum-one-provider.tsx index aaf20e9070..890f31aa9c 100644 --- a/apps/remix-ide/src/app/providers/injected-arbitrum-one-provider.tsx +++ b/apps/remix-ide/src/app/providers/injected-arbitrum-one-provider.tsx @@ -1,5 +1,5 @@ import * as packageJson from '../../../../../package.json' -import { InjectedL2Provider } from './injected-L2-provider' +import {InjectedCustomProvider} from './injected-custom-provider' const profile = { name: 'injected-arbitrum-one-provider', @@ -10,9 +10,8 @@ const profile = { version: packageJson.version } -export class InjectedArbitrumOneProvider extends InjectedL2Provider { - - constructor () { +export class InjectedArbitrumOneProvider extends InjectedCustomProvider { + constructor() { super(profile, 'Arbitrum One', '0xa4b1', ['https://arb1.arbitrum.io/rpc']) } -} \ No newline at end of file +} diff --git a/apps/remix-ide/src/app/providers/injected-custom-provider.tsx b/apps/remix-ide/src/app/providers/injected-custom-provider.tsx new file mode 100644 index 0000000000..90b81c7263 --- /dev/null +++ b/apps/remix-ide/src/app/providers/injected-custom-provider.tsx @@ -0,0 +1,59 @@ +import {InjectedProviderDefaultBase} from './injected-provider-default' + +export class InjectedCustomProvider extends InjectedProviderDefaultBase { + chainName: string + chainId: string + rpcUrls: Array + nativeCurrency: Record + blockExplorerUrls: Array + + constructor(profile: any, chainName: string, chainId: string, rpcUrls: Array, nativeCurrency?: Record, blockExplorerUrls?: Array) { + super(profile) + this.chainName = chainName + this.chainId = chainId + this.rpcUrls = rpcUrls + this.nativeCurrency = nativeCurrency + this.blockExplorerUrls = blockExplorerUrls + } + + async init() { + await super.init() + if (this.chainName && this.rpcUrls && this.rpcUrls.length > 0) await addCustomNetwork(this.chainName, this.chainId, this.rpcUrls, this.nativeCurrency, this.blockExplorerUrls) + else throw new Error('Cannot add the custom network to main injected provider') + return {} + } +} + +export const addCustomNetwork = async (chainName: string, chainId: string, rpcUrls: Array, nativeCurrency?: Record, blockExplorerUrls?: Array) => { + try { + await (window as any).ethereum.request({ + method: 'wallet_switchEthereumChain', + params: [{chainId: chainId}] + }) + } catch (switchError) { + // This error code indicates that the chain has not been added to MetaMask. + if (switchError.code === 4902) { + try { + const paramsObj: Record = { + chainId: chainId, + chainName: chainName, + rpcUrls: rpcUrls, + } + if (nativeCurrency) paramsObj.nativeCurrency = nativeCurrency + if (blockExplorerUrls) paramsObj.blockExplorerUrls = blockExplorerUrls + await (window as any).ethereum.request({ + method: 'wallet_addEthereumChain', + params: [ paramsObj ] + }) + + await (window as any).ethereum.request({ + method: 'wallet_switchEthereumChain', + params: [{chainId: chainId}] + }) + } catch (addError) { + // handle "add" error + } + } + // handle other "switch" errors + } +} diff --git a/apps/remix-ide/src/app/providers/injected-ephemery-testnet-provider.tsx b/apps/remix-ide/src/app/providers/injected-ephemery-testnet-provider.tsx new file mode 100644 index 0000000000..879c468b6a --- /dev/null +++ b/apps/remix-ide/src/app/providers/injected-ephemery-testnet-provider.tsx @@ -0,0 +1,40 @@ +import * as packageJson from '../../../../../package.json' +import {InjectedCustomProvider} from './injected-custom-provider' +import Web3 from 'web3' + +const profile = { + name: 'injected-ephemery-testnet-provider', + displayName: 'Injected Ephemery Testnet Provider', + kind: 'provider', + description: 'Injected Ephemery Testnet Provider', + methods: ['sendAsync', 'init'], + version: packageJson.version +} + +export class InjectedEphemeryTestnetProvider extends InjectedCustomProvider { + constructor() { + super(profile, + 'Ephemery Testnet', + '', + ['https://otter.bordel.wtf/erigon', 'https://eth.ephemeral.zeus.fyi'], + { + "name": "Ephemery ETH", + "symbol": "ETH", + "decimals": 18 + }, + [ + 'https://otter.bordel.wtf/', + 'https://explorer.ephemery.dev/' + ] + ) + } + + async init() { + const chainId = await new Web3(this.rpcUrls[0]).eth.getChainId() + this.chainId = `0x${chainId.toString(16)}` + this.chainName = `Ephemery Testnet ${chainId}` + await super.init() + return {} + } + +} diff --git a/apps/remix-ide/src/app/providers/injected-optimism-provider.tsx b/apps/remix-ide/src/app/providers/injected-optimism-provider.tsx index 60037f415b..592ae28b1a 100644 --- a/apps/remix-ide/src/app/providers/injected-optimism-provider.tsx +++ b/apps/remix-ide/src/app/providers/injected-optimism-provider.tsx @@ -1,5 +1,5 @@ import * as packageJson from '../../../../../package.json' -import { InjectedL2Provider } from './injected-L2-provider' +import {InjectedCustomProvider} from './injected-custom-provider' const profile = { name: 'injected-optimism-provider', @@ -10,9 +10,8 @@ const profile = { version: packageJson.version } -export class Injected0ptimismProvider extends InjectedL2Provider { - - constructor () { +export class Injected0ptimismProvider extends InjectedCustomProvider { + constructor() { super(profile, 'Optimism', '0xa', ['https://mainnet.optimism.io']) } -} \ No newline at end of file +} diff --git a/apps/remix-ide/src/app/providers/injected-provider-default.tsx b/apps/remix-ide/src/app/providers/injected-provider-default.tsx index 9af45e5660..7223d945f2 100644 --- a/apps/remix-ide/src/app/providers/injected-provider-default.tsx +++ b/apps/remix-ide/src/app/providers/injected-provider-default.tsx @@ -1,25 +1,25 @@ /* global ethereum */ import * as packageJson from '../../../../../package.json' -import { InjectedProvider } from './injected-provider' +import {InjectedProvider} from './injected-provider' -export class InjectedProviderDefaultBase extends InjectedProvider { - constructor (profile) { +export class InjectedProviderDefaultBase extends InjectedProvider { + constructor(profile) { super(profile) } - async init () { + async init() { const injectedProvider = this.getInjectedProvider() if (injectedProvider && injectedProvider._metamask && injectedProvider._metamask.isUnlocked) { - if (!await injectedProvider._metamask.isUnlocked()) this.call('notification', 'toast', 'Please make sure the injected provider is unlocked (e.g Metamask).') + if (!(await injectedProvider._metamask.isUnlocked())) this.call('notification', 'toast', 'Please make sure the injected provider is unlocked (e.g Metamask).') } return super.init() } - getInjectedProvider () { + getInjectedProvider() { return (window as any).ethereum } - notFound () { + notFound() { return 'No injected provider found. Make sure your provider (e.g. MetaMask, ...) is active and running (when recently activated you may have to reload the page).' } } @@ -34,7 +34,7 @@ const profile = { } export class InjectedProviderDefault extends InjectedProviderDefaultBase { - constructor () { + constructor() { super(profile) } } diff --git a/apps/remix-ide/src/app/providers/injected-provider-trustwallet.tsx b/apps/remix-ide/src/app/providers/injected-provider-trustwallet.tsx index c58f6d12f8..f7f139fed8 100644 --- a/apps/remix-ide/src/app/providers/injected-provider-trustwallet.tsx +++ b/apps/remix-ide/src/app/providers/injected-provider-trustwallet.tsx @@ -1,6 +1,6 @@ /* global ethereum */ import * as packageJson from '../../../../../package.json' -import { InjectedProvider } from './injected-provider' +import {InjectedProvider} from './injected-provider' const profile = { name: 'injected-trustwallet', @@ -11,16 +11,16 @@ const profile = { version: packageJson.version } -export class InjectedProviderTrustWallet extends InjectedProvider { - constructor () { +export class InjectedProviderTrustWallet extends InjectedProvider { + constructor() { super(profile) } - getInjectedProvider () { + getInjectedProvider() { return (window as any).trustwallet } - notFound () { + notFound() { return 'Could not find Trust Wallet provider. Please make sure the Trust Wallet extension is active. Download the latest version from https://trustwallet.com/browser-extension' } } diff --git a/apps/remix-ide/src/app/providers/injected-provider.tsx b/apps/remix-ide/src/app/providers/injected-provider.tsx index 9a1f915128..c1ac29256e 100644 --- a/apps/remix-ide/src/app/providers/injected-provider.tsx +++ b/apps/remix-ide/src/app/providers/injected-provider.tsx @@ -1,15 +1,15 @@ /* global ethereum */ import React from 'react' // eslint-disable-line -import { Plugin } from '@remixproject/engine' -import { JsonDataRequest, RejectRequest, SuccessRequest } from '../providers/abstract-provider' -import { IProvider } from './abstract-provider' +import {Plugin} from '@remixproject/engine' +import {JsonDataRequest, RejectRequest, SuccessRequest} from '../providers/abstract-provider' +import {IProvider} from './abstract-provider' export abstract class InjectedProvider extends Plugin implements IProvider { - options: { [id: string] : any } = {} + options: {[id: string]: any} = {} listenerAccountsChanged: (accounts: Array) => void listenerChainChanged: (chainId: number) => void - constructor (profile) { + constructor(profile) { super(profile) this.listenerAccountsChanged = (accounts: Array) => { this.emit('accountsChanged', accounts) @@ -25,11 +25,11 @@ export abstract class InjectedProvider extends Plugin implements IProvider { onActivation(): void { try { const web3Provider = this.getInjectedProvider() - web3Provider.on('accountsChanged', this.listenerAccountsChanged); - web3Provider.on('chainChanged', this.listenerChainChanged); + web3Provider.on('accountsChanged', this.listenerAccountsChanged) + web3Provider.on('chainChanged', this.listenerChainChanged) } catch (error) { console.log('unable to listen on context changed') - } + } } onDeactivation(): void { @@ -39,25 +39,23 @@ export abstract class InjectedProvider extends Plugin implements IProvider { web3Provider.removeListener('chainChanged', this.listenerChainChanged) } catch (error) { console.log('unable to remove listener on context changed') - } + } } - askPermission (throwIfNoInjectedProvider) { + askPermission(throwIfNoInjectedProvider) { const web3Provider = this.getInjectedProvider() - if (typeof web3Provider !== "undefined" && typeof web3Provider.request === "function") { - web3Provider.request({ method: "eth_requestAccounts" }) + if (typeof web3Provider !== 'undefined' && typeof web3Provider.request === 'function') { + web3Provider.request({method: 'eth_requestAccounts'}) } else if (throwIfNoInjectedProvider) { throw new Error(this.notFound()) } } - body (): JSX.Element { - return ( -
- ) + body(): JSX.Element { + return
} - async init () { + async init() { const injectedProvider = this.getInjectedProvider() if (injectedProvider === undefined) { this.call('notification', 'toast', this.notFound()) @@ -68,38 +66,58 @@ export abstract class InjectedProvider extends Plugin implements IProvider { return {} } - sendAsync (data: JsonDataRequest): Promise { + sendAsync(data: JsonDataRequest): Promise { return new Promise((resolve, reject) => { this.sendAsyncInternal(data, resolve, reject) }) } - private async sendAsyncInternal (data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise { + private async sendAsyncInternal(data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise { // Check the case where current environment is VM on UI and it still sends RPC requests // This will be displayed on UI tooltip as 'cannot get account list: Environment Updated !!' const web3Provider = this.getInjectedProvider() if (!web3Provider) { this.call('notification', 'toast', 'No injected provider (e.g Metamask) has been found.') - return resolve({ jsonrpc: '2.0', error: 'no injected provider found', id: data.id }) + return resolve({ + jsonrpc: '2.0', + error: 'no injected provider found', + id: data.id + }) } try { let resultData if (web3Provider.send) resultData = await web3Provider.send(data.method, data.params) - else if (web3Provider.request) resultData = await web3Provider.request({ method: data.method, params: data.params}) + else if (web3Provider.request) + resultData = await web3Provider.request({ + method: data.method, + params: data.params + }) else { - resolve({ jsonrpc: '2.0', error: 'provider not valid', id: data.id }) + resolve({jsonrpc: '2.0', error: 'provider not valid', id: data.id}) return } if (resultData) { if (resultData.jsonrpc && resultData.jsonrpc === '2.0') { resultData = resultData.result } - resolve({ jsonrpc: '2.0', result: resultData, id: data.id }) + resolve({jsonrpc: '2.0', result: resultData, id: data.id}) } else { - resolve({ jsonrpc: '2.0', error: 'no return data provided', id: data.id }) + resolve({jsonrpc: '2.0', error: 'no return data provided', id: data.id}) } } catch (error) { - resolve({ jsonrpc: '2.0', error: error.data && error.data.message ? error.data.message : error.message, id: data.id }) + if (error.data && error.data.originalError && error.data.originalError.data) { + resolve({ + jsonrpc: '2.0', + error: error.data.originalError.message, + errorData: error.data.originalError.data, + id: data.id + }) + } else + resolve({ + jsonrpc: '2.0', + error: error.data && error.data.message ? error.data.message : error.message, + id: data.id + }) } } } diff --git a/apps/remix-ide/src/app/providers/injected-skale-chaos-testnet-provider.tsx b/apps/remix-ide/src/app/providers/injected-skale-chaos-testnet-provider.tsx new file mode 100644 index 0000000000..81716a6aa8 --- /dev/null +++ b/apps/remix-ide/src/app/providers/injected-skale-chaos-testnet-provider.tsx @@ -0,0 +1,27 @@ +import * as packageJson from '../../../../../package.json' +import { InjectedCustomProvider } from './injected-custom-provider' + +const profile = { + name: 'injected-skale-chaos-testnet-provider', + displayName: 'Injected SKALE Chaos Testnet', + kind: 'provider', + description: 'Injected SKALE Chaos Testnet Provider', + methods: ['sendAsync', 'init'], + version: packageJson.version +} + +export class InjectedSKALEChaosTestnetProvider extends InjectedCustomProvider { + + constructor () { + super(profile, + 'SKALE Chaos Testnet', + '0x50877ed6', + ['https://staging-v3.skalenodes.com/v1/staging-fast-active-bellatrix'], + { + "name": "sFUEL", + "symbol": "sFUEL", + "decimals": 18 + } + ) + } +} diff --git a/apps/remix-ide/src/app/providers/mainnet-vm-fork-provider.tsx b/apps/remix-ide/src/app/providers/mainnet-vm-fork-provider.tsx index 68fc03e5ba..39747d9be1 100644 --- a/apps/remix-ide/src/app/providers/mainnet-vm-fork-provider.tsx +++ b/apps/remix-ide/src/app/providers/mainnet-vm-fork-provider.tsx @@ -1,29 +1,32 @@ import * as packageJson from '../../../../../package.json' -import { BasicVMProvider } from './vm-provider' +import {BasicVMProvider} from './vm-provider' export class MainnetForkVMProvider extends BasicVMProvider { nodeUrl: string blockNumber: number | 'latest' - constructor (blockchain) { - super({ - name: 'vm-mainnet-fork', - displayName: 'Mainet fork -Remix VM (London)', - kind: 'provider', - description: 'Remix VM (London)', - methods: ['sendAsync', 'init'], - version: packageJson.version - }, blockchain) + constructor(blockchain) { + super( + { + name: 'vm-mainnet-fork', + displayName: 'Mainet fork -Remix VM (London)', + kind: 'provider', + description: 'Remix VM (London)', + methods: ['sendAsync', 'init'], + version: packageJson.version + }, + blockchain + ) this.blockchain = blockchain this.fork = 'shanghai' this.nodeUrl = 'https://mainnet.infura.io/v3/08b2a484451e4635a28b3d8234f24332' this.blockNumber = 'latest' } - async init () { + async init() { return { - 'fork': this.fork, - 'nodeUrl': this.nodeUrl, - 'blockNumber': this.blockNumber + fork: this.fork, + nodeUrl: this.nodeUrl, + blockNumber: this.blockNumber } } } diff --git a/apps/remix-ide/src/app/providers/sepolia-vm-fork-provider.tsx b/apps/remix-ide/src/app/providers/sepolia-vm-fork-provider.tsx index 042bd0ed7c..03d7248adb 100644 --- a/apps/remix-ide/src/app/providers/sepolia-vm-fork-provider.tsx +++ b/apps/remix-ide/src/app/providers/sepolia-vm-fork-provider.tsx @@ -1,29 +1,32 @@ import * as packageJson from '../../../../../package.json' -import { BasicVMProvider } from './vm-provider' +import {BasicVMProvider} from './vm-provider' export class SepoliaForkVMProvider extends BasicVMProvider { nodeUrl: string blockNumber: number | 'latest' - constructor (blockchain) { - super({ - name: 'vm-sepolia-fork', - displayName: 'Sepolia fork - Remix VM (London)', - kind: 'provider', - description: 'Remix VM (London)', - methods: ['sendAsync', 'init'], - version: packageJson.version - }, blockchain) + constructor(blockchain) { + super( + { + name: 'vm-sepolia-fork', + displayName: 'Sepolia fork - Remix VM (London)', + kind: 'provider', + description: 'Remix VM (London)', + methods: ['sendAsync', 'init'], + version: packageJson.version + }, + blockchain + ) this.blockchain = blockchain this.fork = 'shanghai' this.nodeUrl = 'https://remix-sepolia.ethdevops.io' this.blockNumber = 'latest' } - async init () { + async init() { return { - 'fork': this.fork, - 'nodeUrl': this.nodeUrl, - 'blockNumber': this.blockNumber + fork: this.fork, + nodeUrl: this.nodeUrl, + blockNumber: this.blockNumber } } } diff --git a/apps/remix-ide/src/app/providers/vm-provider.tsx b/apps/remix-ide/src/app/providers/vm-provider.tsx index 5e66152463..aa1583f596 100644 --- a/apps/remix-ide/src/app/providers/vm-provider.tsx +++ b/apps/remix-ide/src/app/providers/vm-provider.tsx @@ -1,41 +1,41 @@ import React from 'react' // eslint-disable-line import * as packageJson from '../../../../../package.json' -import { JsonDataRequest, RejectRequest, SuccessRequest } from '../providers/abstract-provider' -import { Plugin } from '@remixproject/engine' -import { IProvider } from './abstract-provider' +import {JsonDataRequest, RejectRequest, SuccessRequest} from '../providers/abstract-provider' +import {Plugin} from '@remixproject/engine' +import {IProvider} from './abstract-provider' export class BasicVMProvider extends Plugin implements IProvider { blockchain fork: string - options: { [id: string] : any } = {} - constructor (profile, blockchain) { + options: {[id: string]: any} = {} + constructor(profile, blockchain) { super(profile) this.blockchain = blockchain this.fork = '' } - async init (): Promise<{ [id: string] : any }> { return {} } + async init(): Promise<{[id: string]: any}> { + return {} + } - body (): JSX.Element { - return ( -
- ) + body(): JSX.Element { + return
} - sendAsync (data: JsonDataRequest): Promise { + sendAsync(data: JsonDataRequest): Promise { return new Promise((resolve, reject) => { this.sendAsyncInternal(data, resolve, reject) }) } - private async sendAsyncInternal (data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise { + private async sendAsyncInternal(data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise { try { await this.blockchain.providers.vm.provider.sendAsync(data, (error, result) => { if (error) return reject(error) else { - resolve({ jsonrpc: '2.0', result, id: data.id }) + resolve({jsonrpc: '2.0', result, id: data.id}) } - }) + }) } catch (error) { reject(error) } @@ -43,61 +43,73 @@ export class BasicVMProvider extends Plugin implements IProvider { } export class MergeVMProvider extends BasicVMProvider { - constructor (blockchain) { - super({ - name: 'vm-merge', - displayName: 'Remix VM (Merge)', - kind: 'provider', - description: 'Remix VM (Merge)', - methods: ['sendAsync', 'init'], - version: packageJson.version - }, blockchain) + constructor(blockchain) { + super( + { + name: 'vm-merge', + displayName: 'Remix VM (Merge)', + kind: 'provider', + description: 'Remix VM (Merge)', + methods: ['sendAsync', 'init'], + version: packageJson.version + }, + blockchain + ) this.blockchain = blockchain this.fork = 'merge' } } export class LondonVMProvider extends BasicVMProvider { - constructor (blockchain) { - super({ - name: 'vm-london', - displayName: 'Remix VM (London)', - kind: 'provider', - description: 'Remix VM (London)', - methods: ['sendAsync', 'init'], - version: packageJson.version - }, blockchain) + constructor(blockchain) { + super( + { + name: 'vm-london', + displayName: 'Remix VM (London)', + kind: 'provider', + description: 'Remix VM (London)', + methods: ['sendAsync', 'init'], + version: packageJson.version + }, + blockchain + ) this.blockchain = blockchain this.fork = 'london' } } export class BerlinVMProvider extends BasicVMProvider { - constructor (blockchain) { - super({ - name: 'vm-berlin', - displayName: 'Remix VM (Berlin)', - kind: 'provider', - description: 'Remix VM (Berlin)', - methods: ['sendAsync', 'init'], - version: packageJson.version - }, blockchain) + constructor(blockchain) { + super( + { + name: 'vm-berlin', + displayName: 'Remix VM (Berlin)', + kind: 'provider', + description: 'Remix VM (Berlin)', + methods: ['sendAsync', 'init'], + version: packageJson.version + }, + blockchain + ) this.blockchain = blockchain this.fork = 'berlin' } } export class ShanghaiVMProvider extends BasicVMProvider { - constructor (blockchain) { - super({ - name: 'vm-shanghai', - displayName: 'Remix VM (Shanghai)', - kind: 'provider', - description: 'Remix VM (Shanghai)', - methods: ['sendAsync', 'init'], - version: packageJson.version - }, blockchain) + constructor(blockchain) { + super( + { + name: 'vm-shanghai', + displayName: 'Remix VM (Shanghai)', + kind: 'provider', + description: 'Remix VM (Shanghai)', + methods: ['sendAsync', 'init'], + version: packageJson.version + }, + blockchain + ) this.blockchain = blockchain this.fork = 'shanghai' } -} \ No newline at end of file +} diff --git a/apps/remix-ide/src/app/state/registry.ts b/apps/remix-ide/src/app/state/registry.ts index dafe13654b..dc3655293f 100644 --- a/apps/remix-ide/src/app/state/registry.ts +++ b/apps/remix-ide/src/app/state/registry.ts @@ -4,35 +4,35 @@ type registryEntry = { } export default class Registry { - private static instance: Registry; - private state: any + private static instance: Registry; + private state: any - private constructor () { - this.state = {} - } - - public static getInstance (): Registry { - if (!Registry.instance) { - Registry.instance = new Registry() - } + private constructor () { + this.state = {} + } - return Registry.instance + public static getInstance (): Registry { + if (!Registry.instance) { + Registry.instance = new Registry() } - public put (entry: registryEntry) { - if (this.state[entry.name]) return this.state[entry.name] - const server = { + return Registry.instance + } + + public put (entry: registryEntry) { + if (this.state[entry.name]) return this.state[entry.name] + const server = { // uid: serveruid, - api: entry.api - } - this.state[entry.name] = { server } - return server + api: entry.api } + this.state[entry.name] = { server } + return server + } - public get (name: string) { - const state = this.state[name] - if (!state) return - const server = state.server - return server - } + public get (name: string) { + const state = this.state[name] + if (!state) return + const server = state.server + return server + } } diff --git a/apps/remix-ide/src/app/tabs/analysis-tab.js b/apps/remix-ide/src/app/tabs/analysis-tab.js index 250cd482b3..9a57c16516 100644 --- a/apps/remix-ide/src/app/tabs/analysis-tab.js +++ b/apps/remix-ide/src/app/tabs/analysis-tab.js @@ -14,7 +14,7 @@ const profile = { methods: [], events: [], icon: 'assets/img/staticAnalysis.webp', - description: 'Checks the contract code for security vulnerabilities and bad practices.', + description: 'Analyze your code using Remix, Solhint and Slither.', kind: 'analysis', location: 'sidePanel', documentation: 'https://remix-ide.readthedocs.io/en/latest/static_analysis.html', @@ -38,6 +38,9 @@ class AnalysisTab extends ViewPlugin { } this.dispatch = null this.hints = [] + this.basicEnabled = false + this.solhintEnabled = false + this.slitherEnabled = false } async onActivation () { @@ -49,16 +52,15 @@ class AnalysisTab extends ViewPlugin { this.event.register('staticAnaysisWarning', (count) => { let payloadType = '' - const error = this.hints.find(hint => hint.type === 'error') - const warning = this.hints.find(hints => hints.type === 'warning') - if (error) { + const error = this.hints?.find(hint => hint.type === 'error') + if (error && this.solhintEnabled) { payloadType = 'error' } else { payloadType = 'warning' } if (count > 0) { - this.emit('statusChanged', { key: count, title: payloadType === 'error' ? `You have some problem${count === 1 ? '' : 's'}` : 'You have some warnings', type: payloadType }) + this.emit('statusChanged', { key: count, title: payloadType === 'error' ? `You have ${count} problem${count === 1 ? '' : 's'}` : `You have ${count} warnings`, type: payloadType }) } else if (count === 0) { this.emit('statusChanged', { key: 'succeed', title: 'no warnings or errors', type: 'success' }) } else { @@ -79,10 +81,10 @@ class AnalysisTab extends ViewPlugin { updateComponent(state) { return + registry={state.registry} + analysisModule={state.analysisModule} + event={state.event} + /> } renderComponent () { diff --git a/apps/remix-ide/src/app/tabs/debugger-tab.js b/apps/remix-ide/src/app/tabs/debugger-tab.js index cd06ea4ffa..03bd672110 100644 --- a/apps/remix-ide/src/app/tabs/debugger-tab.js +++ b/apps/remix-ide/src/app/tabs/debugger-tab.js @@ -5,7 +5,7 @@ import { ViewPlugin } from '@remixproject/engine-web' import * as packageJson from '../../../../../package.json' import React from 'react' // eslint-disable-line import { bleach } from '@remix-ui/helper' -import { compilationFinishedToastMsg, compilingToastMsg, localCompilationToastMsg, notFoundToastMsg, sourceVerificationNotAvailableToastMsg } from '@remix-ui/helper' +import { compilationFinishedToastMsg, compilingToastMsg, notFoundToastMsg, sourceVerificationNotAvailableToastMsg } from '@remix-ui/helper' const css = require('./styles/debugger-tab-styles') const profile = { diff --git a/apps/remix-ide/src/app/tabs/locales/en/debugger.json b/apps/remix-ide/src/app/tabs/locales/en/debugger.json index 87c22efd60..dc46390eed 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/debugger.json +++ b/apps/remix-ide/src/app/tabs/locales/en/debugger.json @@ -2,10 +2,25 @@ "debugger.displayName": "Debugger", "debugger.debuggerConfiguration": "Debugger Configuration", "debugger.stopDebugging": "Stop debugging", + "debugger.provideTxNumber": "Please provide a valid transaction hash", "debugger.startDebugging": "Start debugging", "debugger.placeholder": "Transaction hash, should start with 0x", "debugger.debugLocaNodeLabel": "Force using local node", "debugger.useGeneratedSources": "Use generated sources", "debugger.debugWithGeneratedSources": "When checked, debugger will also step through the compiled .yul file if it exists.", - "debugger.introduction": "When Debugging with a transaction hash, if the contract is verified, Remix will try to fetch the source code from Sourcify or Etherscan. Put in your Etherscan API key in the Remix settings. For supported networks, please see" + "debugger.introduction": "When Debugging with a transaction hash, if the contract is verified, Remix will try to fetch the source code from Sourcify or Etherscan. Put in your Etherscan API key in the Remix settings. For supported networks, please see", + "debugger.forceToUseCurrentLocalNode": "Force the debugger to use the current local node", + "debugger.sourceLocationStatus1": "Locating breakpoint, this might take a while...", + "debugger.sourceLocationStatus2": "Source location not available, neither in Sourcify nor in Etherscan. Please make sure the Etherscan api key is provided in the settings.", + "debugger.sourcifyDocs": "Sourcify docs", + "debugger.noDataAvailable": "No data available", + "debugger.loadMore": "Load more", + "debugger.copy": "Copy", + "debugger.stepOverBack": "Step over back", + "debugger.stepBack": "Step back", + "debugger.stepInto": "Step into", + "debugger.stepOverForward": "Step over forward", + "debugger.jumpPreviousBreakpoint": "Jump to the previous breakpoint", + "debugger.jumpOut": "Jump out", + "debugger.jumpNextBreakpoint": "Jump to the next breakpoint" } diff --git a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json index ab7222713f..0554b0ffa7 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json +++ b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json @@ -45,6 +45,13 @@ "filePanel.publishFolderToGist": "Publish folder to gist", "filePanel.publishFileToGist": "Publish file to gist", "filePanel.copy": "Copy", + "filePanel.copyFileName": "Copy name", + "filePanel.copyFilePath": "Copy path", + "filePanel.contractflattener": "Flatten", + "filePanel.nahmii-compiler": "Compile for Nahmii", + "filePanel.solidityumlgen": "Generate UML", + "filePanel.doc-gen": "Generate Docs", + "filePanel.solidity": "Compile", "filePanel.paste": "Paste", "filePanel.compile": "Compile", "filePanel.compileForNahmii": "Compile for Nahmii", @@ -66,5 +73,54 @@ "filePanel.features": "Features", "filePanel.upgradeability": "Upgradeability", "filePanel.ok": "OK", - "filePanel.cancel": "Cancel" + "filePanel.yes": "Yes", + "filePanel.cancel": "Cancel", + "filePanel.createNewWorkspace": "create a new workspace", + "filePanel.connectToLocalhost": "connect to localhost", + "filePanel.copiedToClipboard": "Copied to clipboard {path}", + "filePanel.downloadFailed": "Download Failed", + "filePanel.downloadFailedMsg": "Unexpected error while downloading: {error}", + "filePanel.close": "Close", + "filePanel.copyFileFailed": "Copy File Failed", + "filePanel.copyFileFailedMsg": "Unexpected error while copying file: {src}", + "filePanel.copyFolderFailed": "Copy Folder Failed", + "filePanel.copyFolderFailedMsg": "Unexpected error while copying folder: {src}", + "filePanel.runScriptFailed": "Run script failed", + "filePanel.createPublicGist": "Create a public gist", + "filePanel.createPublicGistMsg1": "Are you sure you want to push changes to remote gist file on github.com?", + "filePanel.createPublicGistMsg2": "Are you sure you want to anonymously publish all your files in the {path} folder as a public gist on github.com?", + "filePanel.createPublicGistMsg3": "Are you sure you want to anonymously publish {path} file as a public gist on github.com?", + "filePanel.createPublicGistMsg4": "Are you sure you want to anonymously publish all your files in the {name} workspace as a public gist on github.com?", + "filePanel.deleteMsg": "Are you sure you want to delete", + "filePanel.theseItems": "these items", + "filePanel.thisItem": "this item", + "filePanel.deleteItems": "Delete items", + "filePanel.deleteItem": "Delete item", + "filePanel.globalToast": "Cannot write/modify file system in read only mode.", + "filePanel.basic": "Basic", + "filePanel.blank": "Blank", + "filePanel.multiSigWallet": "MultiSig Wallet", + "filePanel.mintable": "Mintable", + "filePanel.burnable": "Burnable", + "filePanel.pausable": "Pausable", + "filePanel.transparent": "Transparent", + "filePanel.initGitRepoTitle": "Check option to initialize workspace as a new git repository", + "filePanel.switchToBranchTitle1": "Checkout new branch from remote branch", + "filePanel.switchToBranchTitle2": "Checkout to local branch", + "filePanel.readOnly": "read-only", + "filePanel.renameFileFailed": "Rename File Failed", + "filePanel.renameFileFailedMsg": "Unexpected error while renaming: {error}", + "filePanel.fileCreationFailed": "File Creation Failed", + "filePanel.folderCreationFailed": "Folder Creation Failed", + "filePanel.validationError": "Validation Error", + "filePanel.validationErrorMsg": "Special characters are not allowed", + "filePanel.reservedKeyword": "Reserved Keyword", + "filePanel.reservedKeywordMsg": "File name contains Remix reserved keywords. \"{content}\"", + "filePanel.moveFile": "Moving files", + "filePanel.moveFileMsg1": "Are you sure you want to move {src} to {dest}?", + "filePanel.movingFileFailed": "Moving File Failed", + "filePanel.movingFileFailedMsg": "Unexpected error while moving file: {src}", + "filePanel.movingFolderFailed": "Moving Folder Failed", + "filePanel.movingFolderFailedMsg": "Unexpected error while moving folder: {src}", + "filePanel.workspaceActions": "Workspace actions" } diff --git a/apps/remix-ide/src/app/tabs/locales/en/home.json b/apps/remix-ide/src/app/tabs/locales/en/home.json index c892190113..dc76b8d547 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/home.json +++ b/apps/remix-ide/src/app/tabs/locales/en/home.json @@ -6,9 +6,9 @@ "home.learnMore": "Learn more", "home.here": "here", "home.featured": "Featured", - "home.jumpIntoWeb3": "JUMP INTO WEB3", - "home.jumpIntoWeb3More": "More", - "home.jumpIntoWeb3Text": "Remix IDE is part of the Remix Project, a rich toolset that can be used for the entire journey of contract development by users of any knowledge level. Learn more on the Remix Project website.", + "home.jumpIntoWeb3": "WE NEED YOUR HELP", + "home.jumpIntoWeb3More": "Go to survey", + "home.jumpIntoWeb3Text": "Remixers... Have a spare moment? Please help us improve your Remix experience with this one-minute survey.", "home.remixYouTube": "WATCH TO LEARN", "home.remixYouTubeText1": "Video Tips from the Remix Team", "home.remixYouTubeMore": "Watch", @@ -18,9 +18,9 @@ "home.betaTestingText2": "Help us beta test releases now and get a handle on new features!", "home.betaTestingMore": "Sign up", "home.featuredPlugins": "Featured Plugins", - "home.solidityPluginDesc": "Compile, test and analyse smart contract.", + "home.solidityPluginDesc": "Compile, test, and analyze smart contracts.", "home.cookbookDesc": "Find smart contracts, solidity libraries, and discover protocols.", - "home.codeAnalyizerPluginDesc": "Analyze your code using Remix, Sohint and Sslither", + "home.codeAnalyizerPluginDesc": "Analyze your code using Remix, Solhint and Slither.", "home.starkNetPluginDesc": "Compile and deploy contracts with Cairo, a native language for StarkNet.", "home.solhintPluginDesc": "Solhint is an open source project for linting Solidity code.", "home.sourcifyPluginDesc": "Solidity contract and metadata verification service.", @@ -47,7 +47,7 @@ "home.remixTwitterProfile": "Remix Twitter Profile", "home.remixLinkedinProfile": "Remix Linkedin Profile", "home.remixMediumPosts": "Remix Medium Posts", - "home.remixGitterChannel": "Join us on Discord", + "home.joinUsOnDiscord": "Join us on Discord", "home.nativeIDE": "The Native IDE for Web3 Development.", "home.website": "Website", "home.documentation": "Documentation", @@ -57,7 +57,10 @@ "home.files": "Files", "home.newFile": "New File", "home.openFile": "Open File", - "home.connectToLocalhost": "Access File System", + "home.accessFileSystem": "Access File System", "home.loadFrom": "Load from", - "home.resources": "Resources" + "home.resources": "Resources", + "home.connectToLocalhost": "Connect to Localhost", + "home.seeAllTutorials": "See all tutorials", + "home.maintainedByRemix": "Maintained by Remix" } diff --git a/apps/remix-ide/src/app/tabs/locales/en/index.js b/apps/remix-ide/src/app/tabs/locales/en/index.js index e01a36e939..59884f426a 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/index.js +++ b/apps/remix-ide/src/app/tabs/locales/en/index.js @@ -11,6 +11,9 @@ import udappJson from './udapp.json'; import solidityUnitTestingJson from './solidityUnitTesting.json'; import permissionHandlerJson from './permissionHandler.json'; import electronJson from './electron.json'; +import solUmlGenJson from './solUmlGen.json' +import remixAppJson from './remixApp.json' +import remixUiTabsJson from './remixUiTabs.json' export default { ...debuggerJson, @@ -25,5 +28,8 @@ export default { ...udappJson, ...solidityUnitTestingJson, ...permissionHandlerJson, - ...electronJson + ...electronJson, + ...solUmlGenJson, + ...remixAppJson, + ...remixUiTabsJson, } diff --git a/apps/remix-ide/src/app/tabs/locales/en/panel.json b/apps/remix-ide/src/app/tabs/locales/en/panel.json index 070dbbd57f..c9ad7d8d05 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/panel.json +++ b/apps/remix-ide/src/app/tabs/locales/en/panel.json @@ -2,5 +2,9 @@ "panel.author": "Author", "panel.maintainedBy": "Maintained By", "panel.documentation": "Documentation", - "panel.description": "Description" + "panel.description": "Description", + "panel.maintainedByRemix": "Maintained by Remix", + "panel.pluginInfo": "Plugin info", + "panel.linkToDoc": "Link to documentation", + "panel.makeAnissue": "Make an issue" } diff --git a/apps/remix-ide/src/app/tabs/locales/en/pluginManager.json b/apps/remix-ide/src/app/tabs/locales/en/pluginManager.json index 01287713d6..de15f35427 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/pluginManager.json +++ b/apps/remix-ide/src/app/tabs/locales/en/pluginManager.json @@ -19,6 +19,10 @@ "pluginManager.localForm.sidePanel": "Side Panel", "pluginManager.localForm.mainPanel": "Main Panel", "pluginManager.localForm.none": "None", + "pluginManager.localForm.methods": "Methods", + "pluginManager.localForm.pluginNames": "Plugin names", + "pluginManager.localForm.ok": "OK", + "pluginManager.localForm.cancel": "Cancel", "pluginManager.Permissions": "Permissions", "pluginManager.permissions": "permissions", "pluginManager.pluginManagerPermissions": "Plugin Manager Permissions", @@ -27,5 +31,13 @@ "pluginManager.allow": "Allow", "pluginManager.toCall": "to call", "pluginManager.ok": "OK", - "pluginManager.cancel": "Cancel" + "pluginManager.cancel": "Cancel", + "pluginManager.maintainedByRemix": "Maintained by Remix", + "pluginManager.linkToDoc": "Link to documentation", + "pluginManager.versionAlpha": "Version Alpha", + "pluginManager.versionBeta": "Version Beta", + "pluginManager.deactivatePlugin": "Deactivate {pluginName}", + "pluginManager.activatePlugin": "Activate {pluginName}", + "pluginManager.search": "Search", + "pluginManager.managePluginsPermissions": "Manage plugins Permissions" } diff --git a/apps/remix-ide/src/app/tabs/locales/en/remixApp.json b/apps/remix-ide/src/app/tabs/locales/en/remixApp.json new file mode 100644 index 0000000000..a67504f413 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/en/remixApp.json @@ -0,0 +1,3 @@ +{ + "remixApp.scrollToSeeAllTabs": "Scroll to see all tabs" +} diff --git a/apps/remix-ide/src/app/tabs/locales/en/remixUiTabs.json b/apps/remix-ide/src/app/tabs/locales/en/remixUiTabs.json new file mode 100644 index 0000000000..1c60e9592d --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/en/remixUiTabs.json @@ -0,0 +1,7 @@ +{ + "remixUiTabs.tooltipText1": "Run script (CTRL + SHIFT + S)", + "remixUiTabs.tooltipText2": "Compile CTRL + S", + "remixUiTabs.tooltipText3": "Select .sol or .yul file to compile or a .ts or .js file and run it", + "remixUiTabs.zoomOut": "Zoom out", + "remixUiTabs.zoomIn": "Zoom in" +} diff --git a/apps/remix-ide/src/app/tabs/locales/en/search.json b/apps/remix-ide/src/app/tabs/locales/en/search.json index 5bb29ab8d2..9eff38fb36 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/search.json +++ b/apps/remix-ide/src/app/tabs/locales/en/search.json @@ -10,5 +10,15 @@ "search.useRegularExpression": "Use Regular Expression", "search.replaceWithoutConfirmation": "replace without confirmation", "search.filesToInclude": "Files to include", - "search.filesToExclude": "Files to exclude" + "search.filesToExclude": "Files to exclude", + "search.toggleReplace": "Toggle Replace", + "search.replaceInFiles": "replace in files", + "search.stop": "stop", + "search.undoChanges": "Undo changes to {path}", + "search.confirmreplaceMsg": "Are you sure you want to replace \"{find}\" by \"{replace}\" in {filename}?", + "search.yes": "Yes", + "search.no": "No", + "search.loading": "Loading", + "search.text1": "showing {count} results in {fileCount} files", + "search.text2": "Too many resuls to display...{br}Please narrow down your search." } diff --git a/apps/remix-ide/src/app/tabs/locales/en/settings.json b/apps/remix-ide/src/app/tabs/locales/en/settings.json index 753a6b67e6..2752f19f75 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/en/settings.json @@ -22,5 +22,19 @@ "settings.themes": "Themes", "settings.locales": "Language", "settings.swarm": "Swarm Settings", - "settings.ipfs": "IPFS Settings" + "settings.ipfs": "IPFS Settings", + "settings.token": "TOKEN", + "settings.copy": "Copy", + "settings.deleteEtherscanToken": "Delete Etherscan token", + "settings.username": "USERNAME", + "settings.email": "EMAIL", + "settings.deleteGithubCredentials": "Delete Github Credentials", + "settings.privateBeeAddress": "PRIVATE BEE ADDRESS", + "settings.postageStampID": "POSTAGE STAMP ID", + "settings.host": "HOST", + "settings.protocol": "PROTOCOL", + "settings.port": "PORT", + "settings.projectID": "PROJECT ID", + "settings.projectSecret": "PROJECT SECRET", + "settings.analyticsInRemix": "Analytics in Remix IDE" } diff --git a/apps/remix-ide/src/app/tabs/locales/en/solUmlGen.json b/apps/remix-ide/src/app/tabs/locales/en/solUmlGen.json new file mode 100644 index 0000000000..5816659c8b --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/en/solUmlGen.json @@ -0,0 +1,10 @@ +{ + "solUmlGen.pngDownload": "Download as PNG", + "solUmlGen.pdfDownload": "Download as PDF", + "solUmlGen.pngDownloadTooltip": "Download UML diagram as a PNG file", + "solUmlGen.pdfDownloadTooltip": "Download UML diagram as a PDF file", + "solUmlGen.text1": "To view your contract as a UML Diagram", + "solUmlGen.text2": "Right click on your contract file", + "solUmlGen.clickOn": "Click on", + "solUmlGen.generateUML": "Generate UML" +} diff --git a/apps/remix-ide/src/app/tabs/locales/en/solUmlgen.json b/apps/remix-ide/src/app/tabs/locales/en/solUmlgen.json deleted file mode 100644 index ca63867e93..0000000000 --- a/apps/remix-ide/src/app/tabs/locales/en/solUmlgen.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "solUml.pngDownload": "Download as PNG", - "solUml.pdfDownload": "Download as PDF" -} \ No newline at end of file diff --git a/apps/remix-ide/src/app/tabs/locales/en/solidity.json b/apps/remix-ide/src/app/tabs/locales/en/solidity.json index 947bfeae94..ad83ce89bb 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/solidity.json +++ b/apps/remix-ide/src/app/tabs/locales/en/solidity.json @@ -1,5 +1,7 @@ { "solidity.displayName": "Solidity compiler", + + "solidity._comment_compiler-container.tsx": "libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx", "solidity.compiler": "Compiler", "solidity.addACustomCompiler": "Add a custom compiler", "solidity.addACustomCompilerWithURL": "Add a custom compiler with URL", @@ -21,11 +23,46 @@ "solidity.compile": "Compile", "solidity.noFileSelected": "no file selected", "solidity.compileAndRunScript": "Compile and Run script", + "solidity.newConfigFileTitle": "New configuration file", + "solidity.newConfigFileMessage": "The file \"{configFilePathInput}\" you entered does not exist. Do you want to create a new one?", + "solidity.create": "Create", + "solidity.ok": "OK", + "solidity.cancel": "Cancel", + "solidity.noFileSelected1": "No file selected.", + "solidity.toCompile": "to compile", + "solidity.noConfigFileSelected": "No config file selected", + "solidity.copyNatSpecTag": "Click to copy the custom NatSpec tag", + "solidity.inputTitle1": "If the file you entered does not exist you will be able to create one in the next step.", + "solidity.inputTitle2": "Estimated number of times each opcode of the deployed code will be executed across the life-time of the contract.", + "solidity.tooltipText1": "Choose the script to execute right after compilation by adding the `dev-run-script` natspec tag, as in:", + "solidity.tooltipText2": "Click the \"i\" icon to learn more", + "solidity.tooltipText3": "for compiling and script execution", + "solidity.tooltipText4": "Click to open the config file", + "solidity.tooltipText5": "Cannot load compiler version list. It might have been blocked by an advertisement blocker. Please try deactivating any of them from this page and reload. Error: ", + "solidity.tooltipText6": "Language specification available from Compiler >= v0.5.7", + "solidity.toastMessage": "Updating compiler version to match current contract file pragma i.e {version}", + "solidity.compileIconAttribute": "compiler is loading, please wait a few moments.", + "solidity.compilerLicense": "Compiler License", + "solidity.compilerLicenseMsg1": "Compiler is loading. License will be displayed once compiler is loaded", + "solidity.compilerLicenseMsg2": "Could not retreive license for selected compiler version", + "solidity.compilerLicenseMsg3": "License not available", + "solidity.seeCompilerLicense": "See compiler license", + + "solidity._comment_contract-selection.tsx": "libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx", "solidity.publishOn": "Publish on", "solidity.flatten": "Flatten contracts before UML generation.", "solidity.generateUML": "Generate a UML diagram of your contract.", "solidity.flattenLabel": "Flatten", "solidity.generateUMLLabel": "Generate UML Diagram", + "solidity.copy": "Copy", + "solidity.copyABI": "Copy ABI to clipboard", + "solidity.copyBytecode": "Copy Bytecode to clipboard", + "solidity.unableToDisplay": "Unable to display", + "solidity.download": "Download", + "solidity.close": "Close", + "solidity.contract": "Contract", + "solidity.displayContractDetails": "Display Contract Details", + "solidity.noContractCompiled": "No Contract Compiled Yet", "solidity.Assembly": "Assembly opcodes describing the contract including corresponding solidity source code", "solidity.Opcodes": "Assembly opcodes describing the contract", "solidity.name": "Name of the compiled contract", @@ -37,5 +74,9 @@ "solidity.functionHashes": "List of declared function and their corresponding hash", "solidity.gasEstimates": "Gas estimation for each function call", "solidity.Runtime Bytecode": "Bytecode storing the state and being executed during normal contract call", + "solidity.storageLayout": "See the Storage Layout documentation.", + "solidity.devdoc": "Developer documentation (natspec)", + "solidity.userdoc": "User documentation (natspec)", + "solidity.compilerInput": "Input to the Solidity compiler", "solidity.swarmLocation": "Swarm url where all metadata information can be found (contract needs to be published first)" } diff --git a/apps/remix-ide/src/app/tabs/locales/en/solidityUnitTesting.json b/apps/remix-ide/src/app/tabs/locales/en/solidityUnitTesting.json index f1080804b6..108883dfe9 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/solidityUnitTesting.json +++ b/apps/remix-ide/src/app/tabs/locales/en/solidityUnitTesting.json @@ -31,5 +31,11 @@ "solidityUnitTesting.assertion": "Assertion", "solidityUnitTesting.expectedValueShouldBe": "Expected value should be", "solidityUnitTesting.receivedValue": "Received value", - "solidityUnitTesting.skippingTheRemainingTests": "Skipping the remaining tests of the function." + "solidityUnitTesting.skippingTheRemainingTests": "Skipping the remaining tests of the function.", + "solidityUnitTesting.toasterMsg": "Folder created successfully", + "solidityUnitTesting.tooltipText1": "At least one contract test failed", + "solidityUnitTesting.tooltipText2": "All contract tests passed", + "solidityUnitTesting.tooltipText3": "Start debugging", + "solidityUnitTesting.fail": "FAIL", + "solidityUnitTesting.pass": "PASS" } diff --git a/apps/remix-ide/src/app/tabs/locales/en/terminal.json b/apps/remix-ide/src/app/tabs/locales/en/terminal.json index a175436686..64a2ac2cab 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/terminal.json +++ b/apps/remix-ide/src/app/tabs/locales/en/terminal.json @@ -13,5 +13,31 @@ "terminal.welcomeText7": "Select a Javascript file in the file explorer and then run `remix.execute()` or `remix.exeCurrent()` in the command line interface", "terminal.welcomeText8": "Right click on a JavaScript file in the file explorer and then click `Run`", "terminal.welcomeText9": "The following libraries are accessible", - "terminal.welcomeText10": "Type the library name to see available commands" + "terminal.welcomeText10": "Type the library name to see available commands", + "terminal.text1": "This type of command has been deprecated and is not functionning anymore. Please run remix.help() to list available commands.", + "terminal.hideTerminal": "Hide Terminal", + "terminal.showTerminal": "Show Terminal", + "terminal.clearConsole": "Clear console", + "terminal.pendingTransactions": "Pending Transactions", + "terminal.toasterMsg1": "no content to execute", + "terminal.toasterMsg2": "provider for path {fileName} not found", + "terminal.vmMode": "VM mode", + "terminal.vmModeMsg": "Cannot debug this call. Debugging calls is only possible in Remix VM mode.", + "terminal.ok": "Ok", + "terminal.cancel": "Cancel", + "terminal.callWarning": "(Cost only applies when called by a contract)", + "terminal.msg1": "Transaction mined but execution failed", + "terminal.msg2": "Transaction mined and execution succeed", + "terminal.msg3": "Status not available at the moment", + "terminal.status": "status", + "terminal.transactionHash": "transaction hash", + "terminal.blockHash": "block hash", + "terminal.blockNumber": "block number", + "terminal.contractAddress": "contract address", + "terminal.transactionCost": "transaction cost", + "terminal.executionCost": "execution cost", + "terminal.input": "input", + "terminal.decodedInput": "decoded input", + "terminal.decodedOutput": "decoded output", + "terminal.logs": "logs" } diff --git a/apps/remix-ide/src/app/tabs/locales/en/udapp.json b/apps/remix-ide/src/app/tabs/locales/en/udapp.json index 3e0571c0b0..d2e2af9193 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/udapp.json +++ b/apps/remix-ide/src/app/tabs/locales/en/udapp.json @@ -1,23 +1,22 @@ { "udapp.displayName": "Deploy & run transactions", + + "udapp._comment_gasPrice.tsx": "libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx", "udapp.gasLimit": "Gas limit", - "udapp.account": "Account", + "udapp.tooltipText4": "The default gas limit is 3M. Adjust as needed.", + + "udapp._comment_value.tsx": "libs/remix-ui/run-tab/src/lib/components/value.tsx", "udapp.value": "Value", + "udapp.tooltipText5": "Enter an amount and choose its unit", + + "udapp._comment_contractDropdownUI.tsx": "libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx", "udapp.contract": "Contract", "udapp.compiledBy": "compiled by {compilerName}", "udapp.warningEvmVersion": "Please make sure that the current network is compatible with this evm version: {evmVersion}. Otherwise any deployment will fail.", "udapp.infoSyncCompiledContractTooltip": "Click here to import contracts compiled from an external framework.This action is enabled when Remix is connected to an external framework (hardhat, truffle, foundry) through remixd.", "udapp.remixIpfsUdappTooltip": "Publishing the source code and metadata to IPFS facilitates source code verification using Sourcify and will greatly foster contract adoption (auditing, debugging, calling it, etc...)", - "udapp.signAMessage": "Sign a message", - "udapp.enterAMessageToSign": "Enter a message to sign", - "udapp.hash": "hash", - "udapp.signature": "signature", - "udapp.signedMessage": "Signed Message", - "udapp.environment": "Environment", - "udapp.environmentDocs": "Click for docs about Environment", "udapp.deploy": "Deploy", "udapp.publishTo": "Publish to", - "udapp.or": "or", "udapp.atAddress": "At Address", "udapp.atAddressOptionsTitle1": "address of contract", "udapp.atAddressOptionsTitle2": "Interact with the deployed contract - requires the .abi file or compiled .sol file to be selected in the editor (with the same compiler configuration)", @@ -26,7 +25,7 @@ "udapp.contractOptionsTitle1": "Please compile *.sol file to deploy or access a contract", "udapp.contractOptionsTitle2": "Select a compiled contract to deploy or to use with At Address.", "udapp.contractOptionsTitle3": "Select and compile *.sol file to deploy or access a contract.", - "udapp.contractOptionsTitle4": "When there is a compiled .sol file, choose the contract to deploy or to use with AtAddress.'", + "udapp.contractOptionsTitle4": "When there is a compiled .sol file, choose the contract to deploy or to use with At Address.", "udapp.checkSumWarning": "It seems you are not using a checksumed address.A checksummed address is an address that contains uppercase letters, as specified in {a}.Checksummed addresses are meant to help prevent users from sending transactions to the wrong address.", "udapp.isOverSizePromptEip170": "Contract creation initialization returns data with length of more than 24576 bytes. The deployment will likely fail if the current network has activated the eip 170. More info: {a}", "udapp.isOverSizePromptEip3860": "Contract creation init code exceeds the allowed max code size of 49152 bytes. The deployment will likely fail if the current network has activated the eip 3860. More info: {a}", @@ -34,9 +33,44 @@ "udapp.noCompiledContracts": "No compiled contracts", "udapp.addressOfContract": "Address of contract", "udapp.loadContractFromAddress": "Load contract from Address", + "udapp.ok": "OK", + "udapp.alert": "Alert", + "udapp.proceed": "Proceed", + "udapp.cancel": "Cancel", + "udapp.abiFileSelected": "ABI file selected", + "udapp.evmVersion": "evm version", + "udapp.addressNotValid": "The address is not valid", + + "udapp._comment_account.tsx": "libs/remix-ui/run-tab/src/lib/components/account.tsx", + "udapp.account": "Account", + "udapp.signAMessage": "Sign a message", + "udapp.enterAMessageToSign": "Enter a message to sign", + "udapp.hash": "hash", + "udapp.signature": "signature", + "udapp.injectedTitle": "Unfortunately it's not possible to create an account using injected provider. Please create the account directly from your provider (i.e metamask or other of the same type).", + "udapp.createNewAccount": "Create a new account", + "udapp.web3Title": "Creating an account is possible only in Personal mode. Please go to Settings to enable it.", + "udapp.defaultTitle": "Unfortunately it's not possible to create an account using an external wallet ({selectExEnv}).", + "udapp.text1": "Please provide a Passphrase for the account creation", + "udapp.tooltipText1": "Account list is empty, please make sure the current provider is properly connected to remix", + "udapp.modalTitle1": "Passphrase to sign a message", + "udapp.modalMessage1": "Enter your passphrase for this account to sign the message", + "udapp.copyAccount": "Copy account to clipboard", + "udapp.signMsgUsingAccount": "Sign a message using this account", + + "udapp._comment_environment.tsx": "libs/remix-ui/run-tab/src/lib/components/environment.tsx", + "udapp.environment": "Environment", + "udapp.environmentDocs": "Click for docs about Environment", + "udapp.tooltipText2": "Open chainlist.org and get the connection specs of the chain you want to interact with.", + "udapp.tooltipText3": "Click to open a bridge for converting L1 mainnet ETH to the selected network currency.", + + "udapp._comment_instanceContainerUI.tsx": "libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx", "udapp.deployedContracts": "Deployed Contracts", "udapp.deployAndRunClearInstances": "Clear instances list and reset recorder", "udapp.deployAndRunNoInstanceText": "Currently you have no contract instances to interact with.", + "udapp.tooltipText6": "Autogenerated generic user interfaces for interaction with deployed contracts", + + "udapp._comment_recorderCardUI.tsx": "libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx", "udapp.transactionsRecorded": "Transactions recorded", "udapp.transactionsCountTooltip": "The number of recorded transactions", "udapp.transactionSaveTooltip1": "No transactions to save", @@ -48,18 +82,70 @@ "udapp.runRecorderTooltip": "Run transaction(s) from the current scenario file", "udapp.save": "Save", "udapp.run": "Run", - "udapp.ok": "OK", - "udapp.alert": "Alert", - "udapp.proceed": "Proceed", - "udapp.cancel": "Cancel", + + "udapp._comment_contractGUI.tsx": "libs/remix-ui/run-tab/src/lib/components/contractGUI.tsx", "udapp.parameters": "Parameters", "udapp.copyParameters": "Copy encoded input parameters to clipboard", "udapp.copyCalldata": "Copy calldata to clipboard", "udapp.deployWithProxy": "Deploy with Proxy", "udapp.upgradeWithProxy": "Upgrade with Proxy", - "udapp.useLastDeployedERC1967Contract": "Use last deployed ERC1967 contract", - "udapp.proxyAddressLabel": "Proxy Address", - "udapp.proxyAddressPlaceholder": "proxy address", - "udapp.proxyAddressInputTooltip": "Enter previously deployed proxy address on the selected network", - "udapp.proxyAddressTooltip": "Select this option to use the last deployed ERC1967 contract on the current network." + "udapp.getEncodedCallError": "cannot encode empty arguments", + "udapp.proxyAddressError1": "proxy address cannot be empty", + "udapp.proxyAddressError2": "not a valid contract address", + "udapp.tooltipText11": "Proxy address cannot be empty", + "udapp.tooltipText12": "Input required", + "udapp.tooltipText13": "Deployed {date}", + + "udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx", + "udapp.tooltipText7": "Remove from the list", + "udapp.tooltipText8": "Click for docs about using 'receive'/'fallback'", + "udapp.tooltipText9": "The Calldata to send to fallback function of the contract.", + "udapp.tooltipText10": "Send data to contract.", + "udapp.balance": "Balance", + "udapp.lowLevelInteractions": "Low level interactions", + "udapp.llIError1": "Value to send should be a number", + "udapp.llIError2": "In order to receive Ether transfer the contract should have either 'receive' or payable 'fallback' function", + "udapp.llIError3": "The calldata should be a valid hexadecimal value with size of at least one byte.", + "udapp.llIError4": "The calldata should be a valid hexadecimal value.", + "udapp.llIError5": "'Fallback' function is not defined", + "udapp.llIError6": "Both 'receive' and 'fallback' functions are not defined", + "udapp.llIError7": "Please define a 'Fallback' function to send calldata and a either 'Receive' or payable 'Fallback' to send ethers", + "udapp.copy": "Copy", + + "udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx", + "udapp.mainnetText1": "You are about to create a transaction on {name} Network. Confirm the details to send the info to your provider.", + "udapp.mainnetText2": "The provider for many users is MetaMask. The provider will ask you to sign the transaction before it is sent to {name} Network.", + "udapp.amount": "Amount", + "udapp.gasEstimation": "Gas estimation", + "udapp.maxPriorityFee": "Max Priority fee", + "udapp.maxFee": "Max fee (Not less than base fee {baseFeePerGas} Gwei)", + "udapp.contractCreation": "Contract Creation", + "udapp.transactionFee": "Transaction is invalid. Max fee should not be less than Base fee", + "udapp.title1": "Represents the part of the tx fee that goes to the miner.", + "udapp.title2": "Represents the maximum amount of fee that you will pay for this transaction. The minimun needs to be set to base fee.", + "udapp.gasPrice": "Gas price", + "udapp.gweiText": "visit {a} for current gas price info.", + "udapp.maxTransactionFee": "Max transaction fee", + "udapp.mainnetText3": "Do not show this warning again.", + + "udapp._comment_run-tab.tsx": "libs/remix-ui/run-tab/src/lib/run-tab.tsx", + "udapp.gasEstimationPromptText": "Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?", + + "udapp._comment_custom-dropdown.tsx": "libs/remix-ui/helper/src/lib/components/custom-dropdown.tsx", + "udapp.enterProxyAddress": "Enter Proxy Address", + + "udapp._comment_provider": "apps/remix-ide/src/app/providers", + "udapp.customVmForkProviderText": "Please provide information about the custom fork. If the node URL is not provided, the VM will start with an empty state.", + "udapp.nodeUrl": "Node URL", + "udapp.blockNumber": "Block number (or \"latest\")", + "udapp.externalHttpProviderText1": "Note: To use Geth & https://remix.ethereum.org, configure it to allow requests from Remix:(see Geth Docs on rpc server)", + "udapp.externalHttpProviderText2": "To run Remix & a local Geth test node, use this command: (see Geth Docs on Dev mode)", + "udapp.externalHttpProviderText3": "WARNING: It is not safe to use the --http.corsdomain flag with a wildcard: --http.corsdomain *", + "udapp.externalHttpProviderText4": "For more info: Remix Docs on External HTTP Provider", + "udapp.foundryProviderText1": "Note: To run Anvil on your system, run:", + "udapp.foundryProviderText2": "For more info, visit: Foundry Documentation", + "udapp.ganacheProviderText1": "Note: To run Ganache on your system, run:", + "udapp.ganacheProviderText2": "For more info, visit: Ganache Documentation", + "udapp.hardhatProviderText1": "Note: To run Hardhat network node on your system, go to hardhat project folder and run command:", + "udapp.hardhatProviderText2": "For more info, visit: Hardhat Documentation" } diff --git a/apps/remix-ide/src/app/tabs/locales/es/home.json b/apps/remix-ide/src/app/tabs/locales/es/home.json index da7c37031e..802d22bef4 100644 --- a/apps/remix-ide/src/app/tabs/locales/es/home.json +++ b/apps/remix-ide/src/app/tabs/locales/es/home.json @@ -6,9 +6,9 @@ "home.learnMore": "Learn more", "home.here": "here", "home.featured": "Featured", - "home.jumpIntoWeb3": "JUMP INTO WEB3", - "home.jumpIntoWeb3More": "More", - "home.jumpIntoWeb3Text": "Remix IDE is part of the Remix Project, a rich toolset that can be used for the entire journey of contract development by users of any knowledge level. Learn more on the Remix Project website.", + "home.jumpIntoWeb3": "WE NEED YOUR HELP", + "home.jumpIntoWeb3More": "Go to survey", + "home.jumpIntoWeb3Text": "Remixers... Have a spare moment? Please help us improve your Remix experience with this one-minute survey.", "home.remixYouTube": "WATCH TO LEARN", "home.remixYouTubeText1": "Video Tips from the Remix Team", "home.remixYouTubeMore": "Watch", @@ -18,7 +18,7 @@ "home.betaTestingText2": "Help us beta test releases now and get a handle on new features!", "home.betaTestingMore": "Sign up", "home.featuredPlugins": "Featured Plugins", - "home.solidityPluginDesc": "Compile, test and analyse smart contract.", + "home.solidityPluginDesc": "Compile, test, and analyze smart contracts.", "home.starkNetPluginDesc": "Compile and deploy contracts with Cairo, a native language for StarkNet.", "home.solhintPluginDesc": "Solhint is an open source project for linting Solidity code.", "home.sourcifyPluginDesc": "Solidity contract and metadata verification service.", diff --git a/apps/remix-ide/src/app/tabs/locales/es/index.js b/apps/remix-ide/src/app/tabs/locales/es/index.js new file mode 100644 index 0000000000..ded9c45b14 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/es/index.js @@ -0,0 +1,36 @@ +import debuggerJson from './debugger.json'; +import filePanelJson from './filePanel.json'; +import homeJson from './home.json'; +import panelJson from './panel.json'; +import pluginManagerJson from './pluginManager.json'; +import searchJson from './search.json'; +import settingsJson from './settings.json'; +import solidityJson from './solidity.json'; +import terminalJson from './terminal.json'; +import udappJson from './udapp.json'; +import solidityUnitTestingJson from './solidityUnitTesting.json'; +import permissionHandlerJson from './permissionHandler.json'; +import solUmlGenJson from './solUmlGen.json' +import remixAppJson from './remixApp.json' +import remixUiTabsJson from './remixUiTabs.json' +import enJson from '../en'; + +// There may have some un-translated content. Always fill in the gaps with EN JSON. +// No need for a defaultMessage prop when render a FormattedMessage component. +export default Object.assign({}, enJson, { + ...debuggerJson, + ...filePanelJson, + ...homeJson, + ...panelJson, + ...pluginManagerJson, + ...searchJson, + ...settingsJson, + ...solidityJson, + ...terminalJson, + ...udappJson, + ...solidityUnitTestingJson, + ...permissionHandlerJson, + ...solUmlGenJson, + ...remixAppJson, + ...remixUiTabsJson, +}) diff --git a/apps/remix-ide/src/app/tabs/locales/es/remixApp.json b/apps/remix-ide/src/app/tabs/locales/es/remixApp.json new file mode 100644 index 0000000000..a67504f413 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/es/remixApp.json @@ -0,0 +1,3 @@ +{ + "remixApp.scrollToSeeAllTabs": "Scroll to see all tabs" +} diff --git a/apps/remix-ide/src/app/tabs/locales/es/remixUiTabs.json b/apps/remix-ide/src/app/tabs/locales/es/remixUiTabs.json new file mode 100644 index 0000000000..1c60e9592d --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/es/remixUiTabs.json @@ -0,0 +1,7 @@ +{ + "remixUiTabs.tooltipText1": "Run script (CTRL + SHIFT + S)", + "remixUiTabs.tooltipText2": "Compile CTRL + S", + "remixUiTabs.tooltipText3": "Select .sol or .yul file to compile or a .ts or .js file and run it", + "remixUiTabs.zoomOut": "Zoom out", + "remixUiTabs.zoomIn": "Zoom in" +} diff --git a/apps/remix-ide/src/app/tabs/locales/es/solUmlGen.json b/apps/remix-ide/src/app/tabs/locales/es/solUmlGen.json new file mode 100644 index 0000000000..5816659c8b --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/es/solUmlGen.json @@ -0,0 +1,10 @@ +{ + "solUmlGen.pngDownload": "Download as PNG", + "solUmlGen.pdfDownload": "Download as PDF", + "solUmlGen.pngDownloadTooltip": "Download UML diagram as a PNG file", + "solUmlGen.pdfDownloadTooltip": "Download UML diagram as a PDF file", + "solUmlGen.text1": "To view your contract as a UML Diagram", + "solUmlGen.text2": "Right click on your contract file", + "solUmlGen.clickOn": "Click on", + "solUmlGen.generateUML": "Generate UML" +} diff --git a/apps/remix-ide/src/app/tabs/locales/es/solUmlgen.json b/apps/remix-ide/src/app/tabs/locales/es/solUmlgen.json deleted file mode 100644 index ca63867e93..0000000000 --- a/apps/remix-ide/src/app/tabs/locales/es/solUmlgen.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "solUml.pngDownload": "Download as PNG", - "solUml.pdfDownload": "Download as PDF" -} \ No newline at end of file diff --git a/apps/remix-ide/src/app/tabs/locales/es/udapp.json b/apps/remix-ide/src/app/tabs/locales/es/udapp.json index 2787d3bd22..48090ab631 100644 --- a/apps/remix-ide/src/app/tabs/locales/es/udapp.json +++ b/apps/remix-ide/src/app/tabs/locales/es/udapp.json @@ -25,7 +25,7 @@ "udapp.contractOptionsTitle1": "Please compile *.sol file to deploy or access a contract", "udapp.contractOptionsTitle2": "Select a compiled contract to deploy or to use with At Address.", "udapp.contractOptionsTitle3": "Select and compile *.sol file to deploy or access a contract.", - "udapp.contractOptionsTitle4": "When there is a compiled .sol file, choose the contract to deploy or to use with AtAddress.'", + "udapp.contractOptionsTitle4": "When there is a compiled .sol file, choose the contract to deploy or to use with At Address.", "udapp.checkSumWarning": "It seems you are not using a checksumed address.A checksummed address is an address that contains uppercase letters, as specified in {a}.Checksummed addresses are meant to help prevent users from sending transactions to the wrong address.", "udapp.isOverSizePromptEip170": "Contract creation initialization returns data with length of more than 24576 bytes. The deployment will likely fail if the current network has activated the eip 170. More info: {a}", "udapp.isOverSizePromptEip3860": "Contract creation init code exceeds the allowed max code size of 49152 bytes. The deployment will likely fail if the current network has activated the eip 3860. More info: {a}", diff --git a/apps/remix-ide/src/app/tabs/locales/fr/home.json b/apps/remix-ide/src/app/tabs/locales/fr/home.json index da7c37031e..802d22bef4 100644 --- a/apps/remix-ide/src/app/tabs/locales/fr/home.json +++ b/apps/remix-ide/src/app/tabs/locales/fr/home.json @@ -6,9 +6,9 @@ "home.learnMore": "Learn more", "home.here": "here", "home.featured": "Featured", - "home.jumpIntoWeb3": "JUMP INTO WEB3", - "home.jumpIntoWeb3More": "More", - "home.jumpIntoWeb3Text": "Remix IDE is part of the Remix Project, a rich toolset that can be used for the entire journey of contract development by users of any knowledge level. Learn more on the Remix Project website.", + "home.jumpIntoWeb3": "WE NEED YOUR HELP", + "home.jumpIntoWeb3More": "Go to survey", + "home.jumpIntoWeb3Text": "Remixers... Have a spare moment? Please help us improve your Remix experience with this one-minute survey.", "home.remixYouTube": "WATCH TO LEARN", "home.remixYouTubeText1": "Video Tips from the Remix Team", "home.remixYouTubeMore": "Watch", @@ -18,7 +18,7 @@ "home.betaTestingText2": "Help us beta test releases now and get a handle on new features!", "home.betaTestingMore": "Sign up", "home.featuredPlugins": "Featured Plugins", - "home.solidityPluginDesc": "Compile, test and analyse smart contract.", + "home.solidityPluginDesc": "Compile, test, and analyze smart contracts.", "home.starkNetPluginDesc": "Compile and deploy contracts with Cairo, a native language for StarkNet.", "home.solhintPluginDesc": "Solhint is an open source project for linting Solidity code.", "home.sourcifyPluginDesc": "Solidity contract and metadata verification service.", diff --git a/apps/remix-ide/src/app/tabs/locales/fr/index.js b/apps/remix-ide/src/app/tabs/locales/fr/index.js new file mode 100644 index 0000000000..ded9c45b14 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/fr/index.js @@ -0,0 +1,36 @@ +import debuggerJson from './debugger.json'; +import filePanelJson from './filePanel.json'; +import homeJson from './home.json'; +import panelJson from './panel.json'; +import pluginManagerJson from './pluginManager.json'; +import searchJson from './search.json'; +import settingsJson from './settings.json'; +import solidityJson from './solidity.json'; +import terminalJson from './terminal.json'; +import udappJson from './udapp.json'; +import solidityUnitTestingJson from './solidityUnitTesting.json'; +import permissionHandlerJson from './permissionHandler.json'; +import solUmlGenJson from './solUmlGen.json' +import remixAppJson from './remixApp.json' +import remixUiTabsJson from './remixUiTabs.json' +import enJson from '../en'; + +// There may have some un-translated content. Always fill in the gaps with EN JSON. +// No need for a defaultMessage prop when render a FormattedMessage component. +export default Object.assign({}, enJson, { + ...debuggerJson, + ...filePanelJson, + ...homeJson, + ...panelJson, + ...pluginManagerJson, + ...searchJson, + ...settingsJson, + ...solidityJson, + ...terminalJson, + ...udappJson, + ...solidityUnitTestingJson, + ...permissionHandlerJson, + ...solUmlGenJson, + ...remixAppJson, + ...remixUiTabsJson, +}) diff --git a/apps/remix-ide/src/app/tabs/locales/fr/remixApp.json b/apps/remix-ide/src/app/tabs/locales/fr/remixApp.json new file mode 100644 index 0000000000..a67504f413 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/fr/remixApp.json @@ -0,0 +1,3 @@ +{ + "remixApp.scrollToSeeAllTabs": "Scroll to see all tabs" +} diff --git a/apps/remix-ide/src/app/tabs/locales/fr/remixUiTabs.json b/apps/remix-ide/src/app/tabs/locales/fr/remixUiTabs.json new file mode 100644 index 0000000000..1c60e9592d --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/fr/remixUiTabs.json @@ -0,0 +1,7 @@ +{ + "remixUiTabs.tooltipText1": "Run script (CTRL + SHIFT + S)", + "remixUiTabs.tooltipText2": "Compile CTRL + S", + "remixUiTabs.tooltipText3": "Select .sol or .yul file to compile or a .ts or .js file and run it", + "remixUiTabs.zoomOut": "Zoom out", + "remixUiTabs.zoomIn": "Zoom in" +} diff --git a/apps/remix-ide/src/app/tabs/locales/fr/solUmlGen.json b/apps/remix-ide/src/app/tabs/locales/fr/solUmlGen.json new file mode 100644 index 0000000000..5816659c8b --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/fr/solUmlGen.json @@ -0,0 +1,10 @@ +{ + "solUmlGen.pngDownload": "Download as PNG", + "solUmlGen.pdfDownload": "Download as PDF", + "solUmlGen.pngDownloadTooltip": "Download UML diagram as a PNG file", + "solUmlGen.pdfDownloadTooltip": "Download UML diagram as a PDF file", + "solUmlGen.text1": "To view your contract as a UML Diagram", + "solUmlGen.text2": "Right click on your contract file", + "solUmlGen.clickOn": "Click on", + "solUmlGen.generateUML": "Generate UML" +} diff --git a/apps/remix-ide/src/app/tabs/locales/fr/solUmlgen.json b/apps/remix-ide/src/app/tabs/locales/fr/solUmlgen.json deleted file mode 100644 index ca63867e93..0000000000 --- a/apps/remix-ide/src/app/tabs/locales/fr/solUmlgen.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "solUml.pngDownload": "Download as PNG", - "solUml.pdfDownload": "Download as PDF" -} \ No newline at end of file diff --git a/apps/remix-ide/src/app/tabs/locales/fr/udapp.json b/apps/remix-ide/src/app/tabs/locales/fr/udapp.json index 2787d3bd22..48090ab631 100644 --- a/apps/remix-ide/src/app/tabs/locales/fr/udapp.json +++ b/apps/remix-ide/src/app/tabs/locales/fr/udapp.json @@ -25,7 +25,7 @@ "udapp.contractOptionsTitle1": "Please compile *.sol file to deploy or access a contract", "udapp.contractOptionsTitle2": "Select a compiled contract to deploy or to use with At Address.", "udapp.contractOptionsTitle3": "Select and compile *.sol file to deploy or access a contract.", - "udapp.contractOptionsTitle4": "When there is a compiled .sol file, choose the contract to deploy or to use with AtAddress.'", + "udapp.contractOptionsTitle4": "When there is a compiled .sol file, choose the contract to deploy or to use with At Address.", "udapp.checkSumWarning": "It seems you are not using a checksumed address.A checksummed address is an address that contains uppercase letters, as specified in {a}.Checksummed addresses are meant to help prevent users from sending transactions to the wrong address.", "udapp.isOverSizePromptEip170": "Contract creation initialization returns data with length of more than 24576 bytes. The deployment will likely fail if the current network has activated the eip 170. More info: {a}", "udapp.isOverSizePromptEip3860": "Contract creation init code exceeds the allowed max code size of 49152 bytes. The deployment will likely fail if the current network has activated the eip 3860. More info: {a}", diff --git a/apps/remix-ide/src/app/tabs/locales/zh/home.json b/apps/remix-ide/src/app/tabs/locales/zh/home.json index ac00d8dce2..17ad8bb36c 100644 --- a/apps/remix-ide/src/app/tabs/locales/zh/home.json +++ b/apps/remix-ide/src/app/tabs/locales/zh/home.json @@ -6,9 +6,9 @@ "home.learnMore": "了解更多", "home.here": "这里", "home.featured": "精选", - "home.jumpIntoWeb3": "迎接 WEB3", - "home.jumpIntoWeb3More": "More", - "home.jumpIntoWeb3Text": "Remix 项目是一个丰富的工具集,任何知识水平的用户都可以在这上面进行全周期的合约开发,并且可作为以太坊教学和实验的学习实验室。", + "home.jumpIntoWeb3": "WE NEED YOUR HELP", + "home.jumpIntoWeb3More": "Go to survey", + "home.jumpIntoWeb3Text": "Remixers... Have a spare moment? Please help us improve your Remix experience with this one-minute survey.", "home.remixYouTube": "观看学习", "home.remixYouTubeText1": "来自 Remix 团队的视频小贴士", "home.remixYouTubeMore": "观看", diff --git a/apps/remix-ide/src/app/tabs/locales/zh/index.js b/apps/remix-ide/src/app/tabs/locales/zh/index.js index 6b77c72871..ded9c45b14 100644 --- a/apps/remix-ide/src/app/tabs/locales/zh/index.js +++ b/apps/remix-ide/src/app/tabs/locales/zh/index.js @@ -10,6 +10,9 @@ import terminalJson from './terminal.json'; import udappJson from './udapp.json'; import solidityUnitTestingJson from './solidityUnitTesting.json'; import permissionHandlerJson from './permissionHandler.json'; +import solUmlGenJson from './solUmlGen.json' +import remixAppJson from './remixApp.json' +import remixUiTabsJson from './remixUiTabs.json' import enJson from '../en'; // There may have some un-translated content. Always fill in the gaps with EN JSON. @@ -27,4 +30,7 @@ export default Object.assign({}, enJson, { ...udappJson, ...solidityUnitTestingJson, ...permissionHandlerJson, + ...solUmlGenJson, + ...remixAppJson, + ...remixUiTabsJson, }) diff --git a/apps/remix-ide/src/app/tabs/locales/zh/remixApp.json b/apps/remix-ide/src/app/tabs/locales/zh/remixApp.json new file mode 100644 index 0000000000..f573c11f1e --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/zh/remixApp.json @@ -0,0 +1,3 @@ +{ + "remixApp.scrollToSeeAllTabs": "滚动查看所有标签页" +} diff --git a/apps/remix-ide/src/app/tabs/locales/zh/remixUiTabs.json b/apps/remix-ide/src/app/tabs/locales/zh/remixUiTabs.json new file mode 100644 index 0000000000..f82e072207 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/zh/remixUiTabs.json @@ -0,0 +1,7 @@ +{ + "remixUiTabs.tooltipText1": "执行脚本 (CTRL + SHIFT + S)", + "remixUiTabs.tooltipText2": "编译 CTRL + S", + "remixUiTabs.tooltipText3": "选择 .sol 或 .yul 文件进行编译,或选择 .ts 或 .js 文件并运行它", + "remixUiTabs.zoomOut": "缩小", + "remixUiTabs.zoomIn": "放大" +} diff --git a/apps/remix-ide/src/app/tabs/locales/zh/solUmlGen.json b/apps/remix-ide/src/app/tabs/locales/zh/solUmlGen.json new file mode 100644 index 0000000000..aa58e68fec --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/zh/solUmlGen.json @@ -0,0 +1,10 @@ +{ + "solUmlGen.pngDownload": "下载 PNG", + "solUmlGen.pdfDownload": "下载 PDF", + "solUmlGen.pngDownloadTooltip": "将 UML 图下载为 PNG 文件", + "solUmlGen.pdfDownloadTooltip": "将 UML 图下载为 PDF 文件", + "solUmlGen.text1": "以 UML 图查看您的合约", + "solUmlGen.text2": "右键单击您的合约文件", + "solUmlGen.clickOn": "点击", + "solUmlGen.generateUML": "生成 UML" +} diff --git a/apps/remix-ide/src/app/tabs/locales/zh/solUmlgen.json b/apps/remix-ide/src/app/tabs/locales/zh/solUmlgen.json deleted file mode 100644 index ca63867e93..0000000000 --- a/apps/remix-ide/src/app/tabs/locales/zh/solUmlgen.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "solUml.pngDownload": "Download as PNG", - "solUml.pdfDownload": "Download as PDF" -} \ No newline at end of file diff --git a/apps/remix-ide/src/app/tabs/network-module.js b/apps/remix-ide/src/app/tabs/network-module.js index c1cc1e12b5..ea7a1c0c6e 100644 --- a/apps/remix-ide/src/app/tabs/network-module.js +++ b/apps/remix-ide/src/app/tabs/network-module.js @@ -53,7 +53,7 @@ export class NetworkModule extends Plugin { this.blockchain.addProvider({ name: network.name, provider }) } - /** Remove a network to the list of availble networks */ + /** Remove a network to the list of available networks */ removeNetwork (name) { this.blockchain.removeProvider(name) } diff --git a/apps/remix-ide/src/app/tabs/search.tsx b/apps/remix-ide/src/app/tabs/search.tsx index 6705428a5f..780ce49bb7 100644 --- a/apps/remix-ide/src/app/tabs/search.tsx +++ b/apps/remix-ide/src/app/tabs/search.tsx @@ -1,33 +1,31 @@ -import { ViewPlugin } from '@remixproject/engine-web' +import {ViewPlugin} from '@remixproject/engine-web' import * as packageJson from '../../../../../package.json' import React from 'react' // eslint-disable-line -import { SearchTab } from '@remix-ui/search' +import {SearchTab} from '@remix-ui/search' const profile = { - name: 'search', - displayName: 'Search in files', - methods: [''], - events: [], - icon: 'assets/img/search_icon.webp', - description: 'Find and replace in file explorer', - kind: '', - location: 'sidePanel', - documentation: '', - version: packageJson.version, - maintainedBy: 'Remix' - } + name: 'search', + displayName: 'Search in files', + methods: [''], + events: [], + icon: 'assets/img/search_icon.webp', + description: 'Find and replace in file explorer', + kind: '', + location: 'sidePanel', + documentation: 'https://remix-ide.readthedocs.io/en/latest/search_in_fe.html', + version: packageJson.version, + maintainedBy: 'Remix' +} export class SearchPlugin extends ViewPlugin { + constructor() { + super(profile) + } - constructor () { - super(profile) - } - - render() { - return ( -
- -
- ); - } - + render() { + return ( +
+ +
+ ) + } } diff --git a/apps/remix-ide/src/app/tabs/settings-tab.tsx b/apps/remix-ide/src/app/tabs/settings-tab.tsx index b68cc0f7f0..cfc168054a 100644 --- a/apps/remix-ide/src/app/tabs/settings-tab.tsx +++ b/apps/remix-ide/src/app/tabs/settings-tab.tsx @@ -1,10 +1,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import React from 'react' // eslint-disable-line -import { ViewPlugin } from '@remixproject/engine-web' +import {ViewPlugin} from '@remixproject/engine-web' import * as packageJson from '../../../../../package.json' -import { RemixUiSettings } from '@remix-ui/settings' //eslint-disable-line +import {RemixUiSettings} from '@remix-ui/settings' //eslint-disable-line import Registry from '../state/registry' -import { PluginViewWrapper } from '@remix-ui/helper' +import {PluginViewWrapper} from '@remix-ui/helper' const profile = { name: 'settings', @@ -18,7 +18,7 @@ const profile = { documentation: 'https://remix-ide.readthedocs.io/en/latest/settings.html', version: packageJson.version, permission: true, - maintainedBy: "Remix" + maintainedBy: 'Remix' } module.exports = class SettingsTab extends ViewPlugin { @@ -31,7 +31,7 @@ module.exports = class SettingsTab extends ViewPlugin { element: HTMLDivElement public useMatomoAnalytics: any dispatch: React.Dispatch = () => {} - constructor (config, editor) { + constructor(config, editor) { super(profile) this.config = config this.config.events.on('configChanged', (changedConfig) => { @@ -47,37 +47,41 @@ module.exports = class SettingsTab extends ViewPlugin { this.useMatomoAnalytics = null } - setDispatch (dispatch: React.Dispatch) { + setDispatch(dispatch: React.Dispatch) { this.dispatch = dispatch this.renderComponent() } render() { - return
- -
+ return ( +
+ +
+ ) } - updateComponent(state: any){ - return + updateComponent(state: any) { + return ( + + ) } - renderComponent () { + renderComponent() { this.dispatch(this) } - get (key) { + get(key) { return this.config.get(key) } - updateMatomoAnalyticsChoice (isChecked) { + updateMatomoAnalyticsChoice(isChecked) { this.config.set('settings/matomo-analytics', isChecked) this.useMatomoAnalytics = isChecked this.dispatch({ diff --git a/apps/remix-ide/src/app/tabs/theme-module.js b/apps/remix-ide/src/app/tabs/theme-module.js index f7bc93f440..b748376ec2 100644 --- a/apps/remix-ide/src/app/tabs/theme-module.js +++ b/apps/remix-ide/src/app/tabs/theme-module.js @@ -6,20 +6,33 @@ import Registry from '../state/registry' const isElectron = require('is-electron') const _paq = window._paq = window._paq || [] +//sol2uml dot files cannot work with css variables so hex values for colors are used const themes = [ - { name: 'Dark', quality: 'dark', url: 'assets/css/themes/remix-dark_tvx1s2.css' }, - { name: 'Light', quality: 'light', url: 'assets/css/themes/remix-light_powaqg.css' }, - { name: 'Violet', quality: 'light', url: 'assets/css/themes/remix-violet.css' }, - { name: 'Unicorn', quality: 'light', url: 'assets/css/themes/remix-unicorn.css' }, - { name: 'Midcentury', quality: 'light', url: 'assets/css/themes/remix-midcentury_hrzph3.css' }, - { name: 'Black', quality: 'dark', url: 'assets/css/themes/remix-black_undtds.css' }, - { name: 'Candy', quality: 'light', url: 'assets/css/themes/remix-candy_ikhg4m.css' }, - { name: 'HackerOwl', quality: 'dark', url: 'assets/css/themes/remix-hacker_owl.css' }, + { name: 'Dark', quality: 'dark', url: 'assets/css/themes/remix-dark_tvx1s2.css', backgroundColor: '#222336', textColor: '#babbcc', + shapeColor: '#babbcc',fillColor: '#2a2c3f' }, + { name: 'Light', quality: 'light', url: 'assets/css/themes/remix-light_powaqg.css', backgroundColor: '#eef1f6', textColor: '#3b445e', + shapeColor: '#343a40',fillColor: '#ffffff' }, + { name: 'Violet', quality: 'light', url: 'assets/css/themes/remix-violet.css', backgroundColor: '#f1eef6', textColor: '#3b445e', + shapeColor: '#343a40',fillColor: '#f8fafe' }, + { name: 'Unicorn', quality: 'light', url: 'assets/css/themes/remix-unicorn.css', backgroundColor: '#f1eef6', textColor: '#343a40', + shapeColor: '#343a40',fillColor: '#f8fafe' }, + { name: 'Midcentury', quality: 'light', url: 'assets/css/themes/remix-midcentury_hrzph3.css', backgroundColor: '#DBE2E0', textColor: '#11556c', + shapeColor: '#343a40',fillColor: '#eeede9' }, + { name: 'Black', quality: 'dark', url: 'assets/css/themes/remix-black_undtds.css', backgroundColor: '#1a1a1a', textColor: '#babbcc', + shapeColor: '#b5b4bc',fillColor: '#1f2020' }, + { name: 'Candy', quality: 'light', url: 'assets/css/themes/remix-candy_ikhg4m.css', backgroundColor: '#d5efff', textColor: '#11556c', + shapeColor: '#343a40',fillColor: '#fbe7f8' }, + { name: 'HackerOwl', quality: 'dark', url: 'assets/css/themes/remix-hacker_owl.css', backgroundColor: '#011628', textColor: '#babbcc', + shapeColor: '#8694a1',fillColor: '#011C32' }, - { name: 'Cerulean', quality: 'light', url: 'assets/css/themes/bootstrap-cerulean.min.css' }, - { name: 'Flatly', quality: 'light', url: 'assets/css/themes/bootstrap-flatly.min.css' }, - { name: 'Spacelab', quality: 'light', url: 'assets/css/themes/bootstrap-spacelab.min.css' }, - { name: 'Cyborg', quality: 'dark', url: 'assets/css/themes/bootstrap-cyborg.min.css' } + { name: 'Cerulean', quality: 'light', url: 'assets/css/themes/bootstrap-cerulean.min.css', backgroundColor: '#ffffff', textColor: '#343a40', + shapeColor: '#343a40',fillColor: '#f8f9fa' }, + { name: 'Flatly', quality: 'light', url: 'assets/css/themes/bootstrap-flatly.min.css', backgroundColor: '#ffffff', textColor: '#343a40', + shapeColor: '#7b8a8b',fillColor: '#ffffff' }, + { name: 'Spacelab', quality: 'light', url: 'assets/css/themes/bootstrap-spacelab.min.css', backgroundColor: '#ffffff', textColor: '#343a40', + shapeColor: '#333333', fillColor: '#eeeeee' }, + { name: 'Cyborg', quality: 'dark', url: 'assets/css/themes/bootstrap-cyborg.min.css', backgroundColor: '#060606', textColor: '#adafae', + shapeColor: '#adafae', fillColor: '#222222' } ] const profile = { @@ -56,7 +69,7 @@ export class ThemeModule extends Plugin { this.forced = !!queryTheme } - /** Return the active theme + /** Return the active theme * @return {{ name: string, quality: string, url: string }} - The active theme */ currentTheme() { @@ -98,7 +111,7 @@ export class ThemeModule extends Plugin { * Change the current theme * @param {string} [themeName] - The name of the theme */ - switchTheme(themeName) { + switchTheme (themeName) { themeName = themeName && themeName.toLocaleLowerCase() if (themeName && !Object.keys(this.themes).includes(themeName)) { throw new Error(`Theme ${themeName} doesn't exist`) diff --git a/apps/remix-ide/src/app/tabs/web3-provider.js b/apps/remix-ide/src/app/tabs/web3-provider.js index f375e52554..0158ff11f9 100644 --- a/apps/remix-ide/src/app/tabs/web3-provider.js +++ b/apps/remix-ide/src/app/tabs/web3-provider.js @@ -60,8 +60,8 @@ export class Web3ProviderModule extends Plugin { reject(new Error('User denied permission')) } }).catch((e) => { - reject(e) - }) + reject(e) + }) }) } diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js index d90246464b..cb6a47b835 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.js +++ b/apps/remix-ide/src/app/udapp/run-tab.js @@ -1,12 +1,12 @@ import React from 'react' // eslint-disable-line -import { RunTabUI } from '@remix-ui/run-tab' -import { ViewPlugin } from '@remixproject/engine-web' -import { addressToString } from '@remix-ui/helper' +import {RunTabUI} from '@remix-ui/run-tab' +import {ViewPlugin} from '@remixproject/engine-web' +import {addressToString} from '@remix-ui/helper' import * as packageJson from '../../../../../package.json' const EventManager = require('../../lib/events') const Recorder = require('../tabs/runTab/model/recorder.js') -const _paq = window._paq = window._paq || [] +const _paq = (window._paq = window._paq || []) const profile = { name: 'udapp', @@ -20,11 +20,21 @@ const profile = { maintainedBy: 'Remix', permission: true, events: ['newTransaction'], - methods: ['createVMAccount', 'sendTransaction', 'getAccounts', 'pendingTransactionsCount', 'getSettings', 'setEnvironmentMode', 'clearAllInstances', 'addInstance', 'resolveContractAndAddInstance'] + methods: [ + 'createVMAccount', + 'sendTransaction', + 'getAccounts', + 'pendingTransactionsCount', + 'getSettings', + 'setEnvironmentMode', + 'clearAllInstances', + 'addInstance', + 'resolveContractAndAddInstance' + ] } export class RunTab extends ViewPlugin { - constructor (blockchain, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, fileProvider) { + constructor(blockchain, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, fileProvider) { super(profile) this.event = new EventManager() this.config = config @@ -41,13 +51,13 @@ export class RunTab extends ViewPlugin { this.el = document.createElement('div') } - setupEvents () { + setupEvents() { this.blockchain.events.on('newTransaction', (tx, receipt) => { this.emit('newTransaction', tx, receipt) }) } - getSettings () { + getSettings() { return new Promise((resolve, reject) => { resolve({ selectedAccount: this.REACT_API.accounts.selectedAccount, @@ -57,48 +67,52 @@ export class RunTab extends ViewPlugin { }) } - async setEnvironmentMode (env) { + async setEnvironmentMode(env) { const canCall = await this.askUserPermission('setEnvironmentMode', 'change the environment used') if (canCall) { - env = typeof env === 'string' ? { context: env } : env + env = typeof env === 'string' ? {context: env} : env this.emit('setEnvironmentModeReducer', env, this.currentRequest.from) } } - clearAllInstances () { + clearAllInstances() { this.emit('clearAllInstancesReducer') } - addInstance (address, abi, name) { + addInstance(address, abi, name) { this.emit('addInstanceReducer', address, abi, name) } - createVMAccount (newAccount) { + createVMAccount(newAccount) { return this.blockchain.createVMAccount(newAccount) } - sendTransaction (tx) { + sendTransaction(tx) { _paq.push(['trackEvent', 'udapp', 'sendTx', 'udappTransaction']) return this.blockchain.sendTransaction(tx) } - getAccounts (cb) { + getAccounts(cb) { return this.blockchain.getAccounts(cb) } - pendingTransactionsCount () { + pendingTransactionsCount() { return this.blockchain.pendingTransactionsCount() } - render () { - return
+ render() { + return ( +
+ +
+ ) } - onReady (api) { + onReady(api) { this.REACT_API = api } - async onInitDone () { + async onInitDone() { const udapp = this // eslint-disable-line const addProvider = async (name, displayName, isInjected, isVM, fork = '', dataId = '', title = '') => { @@ -113,13 +127,13 @@ export class RunTab extends ViewPlugin { title, init: async function () { const options = await udapp.call(name, 'init') - if (options) { + if (options) { this.options = options if (options['fork']) this.fork = options['fork'] } }, provider: { - async sendAsync (payload, callback) { + async sendAsync(payload, callback) { try { const result = await udapp.call(name, 'sendAsync', payload) callback(null, result) @@ -134,10 +148,17 @@ export class RunTab extends ViewPlugin { // basic injected // if it's the trust wallet provider, we have a specific provider for that, see below if (window && window.ethereum && !(window.ethereum.isTrustWallet || window.ethereum.selectedProvider?.isTrustWallet)) { - const displayNameInjected = `Injected Provider${(window && window.ethereum && !(window.ethereum.providers && !window.ethereum.selectedProvider)) ? - window.ethereum.isCoinbaseWallet || window.ethereum.selectedProvider?.isCoinbaseWallet ? ' - Coinbase' : - window.ethereum.isBraveWallet || window.ethereum.selectedProvider?.isBraveWallet ? ' - Brave' : - window.ethereum.isMetaMask || window.ethereum.selectedProvider?.isMetaMask ? ' - MetaMask' : '' : ''}` + const displayNameInjected = `Injected Provider${ + window && window.ethereum && !(window.ethereum.providers && !window.ethereum.selectedProvider) + ? window.ethereum.isCoinbaseWallet || window.ethereum.selectedProvider?.isCoinbaseWallet + ? ' - Coinbase' + : window.ethereum.isBraveWallet || window.ethereum.selectedProvider?.isBraveWallet + ? ' - Brave' + : window.ethereum.isMetaMask || window.ethereum.selectedProvider?.isMetaMask + ? ' - MetaMask' + : '' + : '' + }` await addProvider('injected', displayNameInjected, true, false) } else if (window && !window.ethereum) { // we still add "injected" if there's no provider (just so it's visible to the user). @@ -145,10 +166,10 @@ export class RunTab extends ViewPlugin { } if (window && window.trustwallet) { - const displayNameInjected = `Injected Provider - TrustWallet` + const displayNameInjected = `Injected Provider - TrustWallet` await addProvider('injected-trustwallet', displayNameInjected, true, false) } - + // VM const titleVM = 'Execution environment is local to Remix. Data is only saved to browser memory and will vanish upon reload.' await addProvider('vm-shanghai', 'Remix VM (Shanghai)', false, true, 'shanghai', 'settingsVMShanghaiMode', titleVM) @@ -163,27 +184,31 @@ export class RunTab extends ViewPlugin { // wallet connect await addProvider('walletconnect', 'WalletConnect', false, false) + // testnet + await addProvider('injected-ephemery-testnet-provider', 'Ephemery Testnet', true, false) + await addProvider('injected-skale-chaos-testnet-provider', 'SKALE Chaos Testnet', true, false) + // external provider await addProvider('basic-http-provider', 'Custom - External Http Provider', false, false) await addProvider('hardhat-provider', 'Dev - Hardhat Provider', false, false) await addProvider('ganache-provider', 'Dev - Ganache Provider', false, false) - await addProvider('foundry-provider', 'Dev - Foundry Provider', false, false) - - // injected provider + await addProvider('foundry-provider', 'Dev - Foundry Provider', false, false) + + // injected provider await addProvider('injected-optimism-provider', 'L2 - Optimism Provider', true, false) await addProvider('injected-arbitrum-one-provider', 'L2 - Arbitrum One Provider', true, false) } - writeFile (fileName, content) { + writeFile(fileName, content) { return this.call('fileManager', 'writeFile', fileName, content) } - readFile (fileName) { + readFile(fileName) { return this.call('fileManager', 'readFile', fileName) } - resolveContractAndAddInstance (contractObject, address) { - const data = this.compilersArtefacts.getCompilerAbstract(contractObject.contract.file) + async resolveContractAndAddInstance(contractObject, address) { + const data = await this.compilersArtefacts.getCompilerAbstract(contractObject.contract.file) this.compilersArtefacts.addResolvedContract(addressToString(address), data) this.addInstance(address, contractObject.abi, contractObject.name) 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 b07e2c9432..077d6507f3 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 @@ -31,7 +31,7 @@ export class LandingPage extends ViewPlugin { render () { return
- -
- } + +
+ } } diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css index f46677c2aa..3ed6161e19 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css @@ -2118,6 +2118,7 @@ textarea.form-control { } .btn { + cursor: pointer; display:inline-block; font-weight:400; color:#495057; @@ -2150,7 +2151,8 @@ textarea.form-control { box-shadow:0 0 0 .2rem rgba(47,164,231,.25) } .btn.disabled,.btn:disabled { - opacity:.65 + opacity:.65; + cursor: not-allowed } .btn:not(:disabled):not(.disabled) { cursor:pointer @@ -3928,7 +3930,8 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- padding:1.25rem } .card-title { - margin-bottom:.75rem + margin-bottom:.75rem; + color: var(--text); } .card-subtitle { margin-top:-.375rem; diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css index e2395667b5..136e53ff42 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css @@ -2119,6 +2119,7 @@ textarea.form-control { } .btn { + cursor: pointer;; display:inline-block; font-weight:400; color:#adafae; @@ -2151,7 +2152,8 @@ textarea.form-control { box-shadow:0 0 0 .2rem rgba(42,159,214,.25) } .btn.disabled,.btn:disabled { - opacity:.65 + opacity:.65; + cursor: not-allowed; } .btn:not(:disabled):not(.disabled) { cursor:pointer @@ -2176,9 +2178,9 @@ a.btn.disabled,fieldset:disabled a.btn { box-shadow:0 0 0 .2rem rgba(74,173,220,.5) } .btn-primary.disabled,.btn-primary:disabled { - color:#fff; - background-color:#2a9fd6; - border-color:#2a9fd6 + color: #a6bdcd; + background-color: #327b96; + border-color: #327b96; } .btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle { color:#fff; @@ -3929,7 +3931,8 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- padding:1.25rem } .card-title { - margin-bottom:.75rem + margin-bottom:.75rem; + color: var(--text); } .card-subtitle { margin-top:-.375rem; @@ -4419,9 +4422,9 @@ a.badge-dark.focus,a.badge-dark:focus { color:#311141 } .alert-warning { - color:#854700; - background-color:#ffe7cc; - border-color:#ffdeb8 + color: #fff; + background-color: #ffe7cc; + border-color: #ffdeb8 } .alert-warning hr { border-top-color:#ffd29f diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css index 30a639ca4d..e9b14b99af 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css @@ -2121,6 +2121,7 @@ textarea.form-control { } .btn { + cursor: pointer; display:inline-block; font-weight:400; color:#212529; @@ -2152,7 +2153,8 @@ textarea.form-control { box-shadow:0 0 0 .2rem rgba(44,62,80,.25) } .btn.disabled,.btn:disabled { - opacity:.65 + opacity:.65; + cursor: not-allowed; } .btn:not(:disabled):not(.disabled) { cursor:pointer @@ -3395,7 +3397,8 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- -ms-flex:1 1 auto; flex:1 1 auto; min-height:1px; padding:1.25rem } .card-title { - margin-bottom:.75rem + margin-bottom:.75rem; + color: var(--text); } .card-subtitle { margin-top:-.375rem; margin-bottom:0 diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css index 99373822eb..3129408286 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css @@ -2121,6 +2121,7 @@ textarea.form-control { } .btn { + cursor: pointer; display:inline-block; font-weight:400; color:#777; @@ -2153,7 +2154,8 @@ textarea.form-control { box-shadow:0 0 0 .2rem rgba(68,110,155,.25) } .btn.disabled,.btn:disabled { - opacity:.65 + opacity:.65; + cursor: not-allowed } .btn:not(:disabled):not(.disabled) { cursor:pointer @@ -3931,7 +3933,8 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- padding:1.25rem } .card-title { - margin-bottom:.75rem + margin-bottom:.75rem; + color: var(--text); } .card-subtitle { margin-top:-.375rem; diff --git a/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css b/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css index 0242c30155..5c16277d2e 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css +++ b/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css @@ -2096,6 +2096,7 @@ textarea.form-control.is-invalid { } } .btn { + cursor: pointer; display: inline-block; font-weight: 400; color: #d5d5d5; @@ -2127,6 +2128,7 @@ textarea.form-control.is-invalid { .btn.disabled, .btn:disabled { opacity: 0.65; + cursor: not-allowed } a.btn.disabled, fieldset:disabled a.btn { @@ -2149,7 +2151,7 @@ fieldset:disabled a.btn { .btn-primary.disabled, .btn-primary:disabled { color: #d5d5d5; - background-color: #153844; + background-color: #327b96; border-color: #007aa6; } .btn-primary:not(:disabled):not(.disabled).active, @@ -3371,8 +3373,8 @@ input[type="submit"].btn-block { background-image: none; } .custom-select:disabled { - color: #272626; - background-color: ##222225; + color: #bdbed1; + background-color: #222225; } .custom-select::-ms-expand { display: none; diff --git a/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css b/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css index 99e367a625..73574f8f5f 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css +++ b/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css @@ -2314,6 +2314,7 @@ textarea.form-control.is-invalid { } .btn { + cursor: pointer; display: inline-block; font-weight: 400; color: #0f7292; @@ -2346,6 +2347,7 @@ textarea.form-control.is-invalid { .btn.disabled, .btn:disabled { opacity: 0.7; + cursor: not-allowed } a.btn.disabled, @@ -4371,6 +4373,7 @@ input[type="button"].btn-block { .card-title { margin-bottom: 0.75rem; + color: var(--text); } .card-subtitle { diff --git a/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css b/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css index 63451df9f9..f512a127c8 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css +++ b/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css @@ -2097,6 +2097,7 @@ textarea.form-control.is-invalid { } } .btn { + cursor: pointer; display: inline-block; font-weight: 400; color: #fff; @@ -2128,6 +2129,7 @@ textarea.form-control.is-invalid { .btn.disabled, .btn:disabled { opacity: 0.65; + cursor: not-allowed } a.btn.disabled, fieldset:disabled a.btn { @@ -2149,9 +2151,9 @@ fieldset:disabled a.btn { } .btn-primary.disabled, .btn-primary:disabled { - color: #fff; - background-color: #007aa6; - border-color: #007aa6; + color: #a6bdcd; + background-color: #327b96; + border-color: #327b96; } .btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active, @@ -3371,7 +3373,7 @@ input[type="submit"].btn-block { background-image: none; } .custom-select:disabled { - color: #55566c; + color: #bdbed1; background-color: #282a3d; } .custom-select::-ms-expand { diff --git a/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css b/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css index 1f56d797f7..0ef4225d57 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css +++ b/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css @@ -2111,6 +2111,7 @@ textarea.form-control.is-invalid { } } .btn { + cursor: pointer; display: inline-block; font-weight: 400; color: #fff; @@ -2142,6 +2143,7 @@ textarea.form-control.is-invalid { .btn.disabled, .btn:disabled { opacity: 0.65; + cursor: not-allowed; } a.btn.disabled, fieldset:disabled a.btn { @@ -2163,9 +2165,9 @@ fieldset:disabled a.btn { } .btn-primary.disabled, .btn-primary:disabled { - color: #fff; - background-color: #007aa6; - border-color: #007aa6; + color: #a6bdcd; + background-color: #327b96; + border-color: #327b96; } .btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active, @@ -3385,7 +3387,7 @@ input[type="submit"].btn-block { background-image: none; } .custom-select:disabled { - color: #55566c; + color: #bdbed1; background-color: #282a3d; } .custom-select::-ms-expand { diff --git a/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css b/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css index 8ba6a88f05..3217df2899 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css +++ b/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css @@ -2310,6 +2310,7 @@ textarea.form-control.is-invalid { } .btn { + cursor: pointer; display: inline-block; font-weight: 400; color: #2e3145; @@ -2342,6 +2343,7 @@ textarea.form-control.is-invalid { .btn.disabled, .btn:disabled { opacity: 0.7; + cursor: not-allowed; } a.btn.disabled, @@ -4367,6 +4369,7 @@ input[type="button"].btn-block { .card-title { margin-bottom: 0.75rem; + color: var(--text); } .card-subtitle { diff --git a/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css b/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css index 5df1a16a34..f64bc8d01b 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css +++ b/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css @@ -2315,6 +2315,7 @@ textarea.form-control.is-invalid { } .btn { + cursor: pointer; display: inline-block; font-weight: 400; color: #062809; @@ -2347,6 +2348,7 @@ textarea.form-control.is-invalid { .btn.disabled, .btn:disabled { opacity: 0.7; + cursor: not-allowed; } a.btn.disabled, @@ -4373,6 +4375,7 @@ input[type="button"].btn-block { .card-title { margin-bottom: 0.75rem; + color: var(--text); } .card-subtitle { diff --git a/apps/remix-ide/src/assets/css/themes/remix-unicorn.css b/apps/remix-ide/src/assets/css/themes/remix-unicorn.css index cf627d02c0..ebf508ff83 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-unicorn.css +++ b/apps/remix-ide/src/assets/css/themes/remix-unicorn.css @@ -2313,6 +2313,7 @@ textarea.form-control.is-invalid { } .btn { + cursor: pointer; display: inline-block; font-weight: 400; color: #2e3145; @@ -2346,6 +2347,7 @@ textarea.form-control.is-invalid { .btn.disabled, .btn:disabled { opacity: 0.7; + cursor: not-allowed; } a.btn.disabled, @@ -4371,6 +4373,7 @@ input[type="button"].btn-block { .card-title { margin-bottom: 0.75rem; + color: var(--text); } .card-subtitle { diff --git a/apps/remix-ide/src/assets/css/themes/remix-violet.css b/apps/remix-ide/src/assets/css/themes/remix-violet.css index 0b3f629e81..275d0f0907 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-violet.css +++ b/apps/remix-ide/src/assets/css/themes/remix-violet.css @@ -2310,6 +2310,7 @@ textarea.form-control.is-invalid { } .btn { + cursor: pointer; display: inline-block; font-weight: 400; color: #2e3145; @@ -2342,6 +2343,7 @@ textarea.form-control.is-invalid { .btn.disabled, .btn:disabled { opacity: 0.7; + cursor: not-allowed; } a.btn.disabled, @@ -4367,6 +4369,7 @@ input[type="button"].btn-block { .card-title { margin-bottom: 0.75rem; + color: var(--text); } .card-subtitle { diff --git a/apps/remix-ide/src/assets/img/cookbook.webp b/apps/remix-ide/src/assets/img/cookbook.webp index 4b831b59d4..e3535bbdca 100644 Binary files a/apps/remix-ide/src/assets/img/cookbook.webp and b/apps/remix-ide/src/assets/img/cookbook.webp differ diff --git a/apps/remix-ide/src/assets/js/loader.js b/apps/remix-ide/src/assets/js/loader.js index 51887984c7..8db5546da5 100644 --- a/apps/remix-ide/src/assets/js/loader.js +++ b/apps/remix-ide/src/assets/js/loader.js @@ -30,10 +30,6 @@ if (domains[window.location.hostname]) { var u = "https://ethereumfoundation.matomo.cloud/"; _paq.push(['setTrackerUrl', u + 'matomo.php']); _paq.push(['setSiteId', domains[window.location.hostname]]); - // Send all of the Remix tracking data to the secondary Matomo server (the EF one). - var secondaryTracker = 'https://matomo.ethereum.org/matomo.php'; - var secondaryWebsiteId = domainsSecondaryTracker[window.location.hostname]; - _paq.push(['addTracker', secondaryTracker, secondaryWebsiteId]); var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0]; g.async = true; g.src = '//cdn.matomo.cloud/ethereumfoundation.matomo.cloud/matomo.js'; s.parentNode.insertBefore(g,s); })() diff --git a/apps/remix-ide/src/blockchain/blockchain.tsx b/apps/remix-ide/src/blockchain/blockchain.tsx index e6b719f8d1..c698fd9c40 100644 --- a/apps/remix-ide/src/blockchain/blockchain.tsx +++ b/apps/remix-ide/src/blockchain/blockchain.tsx @@ -1,24 +1,23 @@ - import React from 'react' // eslint-disable-line import Web3 from 'web3' -import { Plugin } from '@remixproject/engine' -import { toBuffer, addHexPrefix } from '@ethereumjs/util' -import { EventEmitter } from 'events' -import { format } from 'util' -import { ExecutionContext } from './execution-context' +import {Plugin} from '@remixproject/engine' +import {toBuffer, addHexPrefix} from '@ethereumjs/util' +import {EventEmitter} from 'events' +import {format} from 'util' +import {ExecutionContext} from './execution-context' import Config from '../config' -import { VMProvider } from './providers/vm' -import { InjectedProvider } from './providers/injected' -import { NodeProvider } from './providers/node' -import { execution, EventManager, helpers } from '@remix-project/remix-lib' -import { etherScanLink } from './helper' -import { logBuilder, cancelUpgradeMsg, cancelProxyMsg, addressToString } from "@remix-ui/helper" -const { txFormat, txExecution, typeConversion, txListener: Txlistener, TxRunner, TxRunnerWeb3, txHelper } = execution -const { txResultHelper } = helpers -const { resultToRemixTx } = txResultHelper +import {VMProvider} from './providers/vm' +import {InjectedProvider} from './providers/injected' +import {NodeProvider} from './providers/node' +import {execution, EventManager, helpers} from '@remix-project/remix-lib' +import {etherScanLink} from './helper' +import {logBuilder, cancelUpgradeMsg, cancelProxyMsg, addressToString} from '@remix-ui/helper' +const {txFormat, txExecution, typeConversion, txListener: Txlistener, TxRunner, TxRunnerWeb3, txHelper} = execution +const {txResultHelper} = helpers +const {resultToRemixTx} = txResultHelper import * as packageJson from '../../../../package.json' -const _paq = window._paq = window._paq || [] //eslint-disable-line +const _paq = (window._paq = window._paq || []) //eslint-disable-line const profile = { name: 'blockchain', @@ -29,19 +28,19 @@ const profile = { } export type TransactionContextAPI = { - getAddress: (cb: (error: Error, result: string) => void) => void, - getValue: (cb: (error: Error, result: string) => void) => void, + getAddress: (cb: (error: Error, result: string) => void) => void + getValue: (cb: (error: Error, result: string) => void) => void getGasLimit: (cb: (error: Error, result: string) => void) => void } // see TxRunner.ts in remix-lib export type Transaction = { - from: string, - to: string, - value: string, - data: string, - gasLimit: number, - useCall: boolean, + from: string + to: string + value: string + data: string + gasLimit: number + useCall: boolean timestamp?: number } @@ -55,16 +54,16 @@ export class Blockchain extends Plugin { networkcallid: number networkStatus: { network: { - name: string, - id: string + name: string + id: string } error?: string } - providers: { [key: string]: VMProvider | InjectedProvider | NodeProvider } + providers: {[key: string]: VMProvider | InjectedProvider | NodeProvider} transactionContextAPI: TransactionContextAPI // NOTE: the config object will need to be refactored out in remix-lib - constructor (config: Config) { + constructor(config: Config) { super(profile) this.active = false this.event = new EventManager() @@ -72,55 +71,61 @@ export class Blockchain extends Plugin { this.events = new EventEmitter() this.config = config - const web3Runner = new TxRunnerWeb3({ - config: this.config, - detectNetwork: (cb) => { - this.executionContext.detectNetwork(cb) + const web3Runner = new TxRunnerWeb3( + { + config: this.config, + detectNetwork: (cb) => { + this.executionContext.detectNetwork(cb) + }, + isVM: () => { + return this.executionContext.isVM() + }, + personalMode: () => { + return this.getProvider() === 'web3' ? this.config.get('settings/personal-mode') : false + } }, - isVM: () => { return this.executionContext.isVM() }, - personalMode: () => { - return this.getProvider() === 'web3' ? this.config.get('settings/personal-mode') : false - } - }, _ => this.executionContext.web3(), _ => this.executionContext.currentblockGasLimit()) + (_) => this.executionContext.web3(), + (_) => this.executionContext.currentblockGasLimit() + ) this.txRunner = new TxRunner(web3Runner, {}) this.networkcallid = 0 - this.networkStatus = { network: { name: ' - ', id: ' - ' } } + this.networkStatus = {network: {name: ' - ', id: ' - '}} this.setupEvents() this.setupProviders() } - _triggerEvent (name, args) { + _triggerEvent(name, args) { if (!this.active) return this.event.trigger(name, args) this.emit(name, ...args) } - onActivation () { + onActivation() { this.active = true this.on('injected', 'chainChanged', () => { this.detectNetwork((error, network) => { - this.networkStatus = { network, error } + this.networkStatus = {network, error} this._triggerEvent('networkStatus', [this.networkStatus]) }) }) this.on('injected-trustwallet', 'chainChanged', () => { this.detectNetwork((error, network) => { - this.networkStatus = { network, error } + this.networkStatus = {network, error} this._triggerEvent('networkStatus', [this.networkStatus]) }) }) this.on('walletconnect', 'chainChanged', () => { this.detectNetwork((error, network) => { - this.networkStatus = { network, error } + this.networkStatus = {network, error} this._triggerEvent('networkStatus', [this.networkStatus]) }) }) } - onDeactivation () { + onDeactivation() { this.active = false this.off('injected', 'chainChanged') this.off('injected-trustwallet', 'chainChanged') @@ -128,12 +133,12 @@ export class Blockchain extends Plugin { this.off('walletconnect', 'accountsChanged') } - setupEvents () { + setupEvents() { this.executionContext.event.register('contextChanged', async (context) => { await this.resetEnvironment() this._triggerEvent('contextChanged', [context]) this.detectNetwork((error, network) => { - this.networkStatus = { network, error } + this.networkStatus = {network, error} this._triggerEvent('networkStatus', [this.networkStatus]) }) }) @@ -148,17 +153,17 @@ export class Blockchain extends Plugin { setInterval(() => { this.detectNetwork((error, network) => { - this.networkStatus = { network, error } + this.networkStatus = {network, error} this._triggerEvent('networkStatus', [this.networkStatus]) }) }, 30000) } - getCurrentNetworkStatus () { + getCurrentNetworkStatus() { return this.networkStatus } - setupProviders () { + setupProviders() { const vmProvider = new VMProvider(this.executionContext) this.providers = {} this.providers['vm'] = vmProvider @@ -166,7 +171,7 @@ export class Blockchain extends Plugin { this.providers.web3 = new NodeProvider(this.executionContext, this.config) } - getCurrentProvider () { + getCurrentProvider() { const provider = this.getProvider() if (provider && provider.startsWith('vm')) return this.providers['vm'] if (this.providers[provider]) return this.providers[provider] @@ -175,7 +180,7 @@ export class Blockchain extends Plugin { /** Return the list of accounts */ // note: the dual promise/callback is kept for now as it was before - getAccounts (cb) { + getAccounts(cb) { return new Promise((resolve, reject) => { this.getCurrentProvider().getAccounts((error, accounts) => { if (cb) { @@ -189,36 +194,53 @@ export class Blockchain extends Plugin { }) } - deployContractAndLibraries (selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) { - const { continueCb, promptCb, statusCb, finalCb } = callbacks + deployContractAndLibraries(selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) { + const {continueCb, promptCb, statusCb, finalCb} = callbacks const constructor = selectedContract.getConstructorInterface() - txFormat.buildData(selectedContract.name, selectedContract.object, compilerContracts, true, constructor, args, (error, data) => { - if (error) { - return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) - } + txFormat.buildData( + selectedContract.name, + selectedContract.object, + compilerContracts, + true, + constructor, + args, + (error, data) => { + if (error) { + return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) + } - statusCb(`creation of ${selectedContract.name} pending...`) - this.createContract(selectedContract, data, continueCb, promptCb, confirmationCb, finalCb) - }, statusCb, (data, runTxCallback) => { - // called for libraries deployment - this.runTx(data, confirmationCb, continueCb, promptCb, runTxCallback) - }) + statusCb(`creation of ${selectedContract.name} pending...`) + this.createContract(selectedContract, data, continueCb, promptCb, confirmationCb, finalCb) + }, + statusCb, + (data, runTxCallback) => { + // called for libraries deployment + this.runTx(data, confirmationCb, continueCb, promptCb, runTxCallback) + } + ) } - deployContractWithLibrary (selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) { - const { continueCb, promptCb, statusCb, finalCb } = callbacks + deployContractWithLibrary(selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) { + const {continueCb, promptCb, statusCb, finalCb} = callbacks const constructor = selectedContract.getConstructorInterface() - txFormat.encodeConstructorCallAndLinkLibraries(selectedContract.object, args, constructor, contractMetadata.linkReferences, selectedContract.bytecodeLinkReferences, (error, data) => { - if (error) { - return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) - } + txFormat.encodeConstructorCallAndLinkLibraries( + selectedContract.object, + args, + constructor, + contractMetadata.linkReferences, + selectedContract.bytecodeLinkReferences, + (error, data) => { + if (error) { + return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) + } - statusCb(`creation of ${selectedContract.name} pending...`) - this.createContract(selectedContract, data, continueCb, promptCb, confirmationCb, finalCb) - }) + statusCb(`creation of ${selectedContract.name} pending...`) + this.createContract(selectedContract, data, continueCb, promptCb, confirmationCb, finalCb) + } + ) } - async deployProxy (proxyData, implementationContractObject) { + async deployProxy(proxyData, implementationContractObject) { const proxyModal = { id: 'confirmProxyDeployment', title: 'Confirm Deploy Proxy (ERC1967)', @@ -240,20 +262,24 @@ export class Blockchain extends Plugin { this.call('notification', 'modal', proxyModal) } - async runProxyTx (proxyData, implementationContractObject) { - const args = { useCall: false, data: proxyData } + async runProxyTx(proxyData, implementationContractObject) { + const args = {useCall: false, data: proxyData} let networkInfo const confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => { networkInfo = network // continue using original authorization given by user continueTxExecution(null) } - const continueCb = (error, continueTxExecution, cancelCb) => { continueTxExecution() } - const promptCb = (okCb, cancelCb) => { okCb() } + const continueCb = (error, continueTxExecution, cancelCb) => { + continueTxExecution() + } + const promptCb = (okCb, cancelCb) => { + okCb() + } const finalCb = async (error, txResult, address, returnValue) => { if (error) { const log = logBuilder(error) - + _paq.push(['trackEvent', 'blockchain', 'Deploy With Proxy', 'Proxy deployment failed: ' + error]) return this.call('terminal', 'logHtml', log) } @@ -287,16 +313,20 @@ export class Blockchain extends Plugin { this.call('notification', 'modal', upgradeModal) } - async runUpgradeTx (proxyAddress, data, newImplementationContractObject) { - const args = { useCall: false, data, to: proxyAddress } + async runUpgradeTx(proxyAddress, data, newImplementationContractObject) { + const args = {useCall: false, data, to: proxyAddress} let networkInfo const confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => { // continue using original authorization given by user networkInfo = network continueTxExecution(null) } - const continueCb = (error, continueTxExecution, cancelCb) => { continueTxExecution() } - const promptCb = (okCb, cancelCb) => { okCb() } + const continueCb = (error, continueTxExecution, cancelCb) => { + continueTxExecution() + } + const promptCb = (okCb, cancelCb) => { + okCb() + } const finalCb = async (error, txResult, address, returnValue) => { if (error) { const log = logBuilder(error) @@ -311,56 +341,83 @@ export class Blockchain extends Plugin { this.runTx(args, confirmationCb, continueCb, promptCb, finalCb) } - async saveDeployedContractStorageLayout (contractObject, proxyAddress, networkInfo) { - const { contractName, implementationAddress } = contractObject - const networkName = networkInfo.name === 'custom' ? networkInfo.name + '-' + networkInfo.id : networkInfo.name - const hasPreviousDeploys = await this.call('fileManager', 'exists', `.deploys/upgradeable-contracts/${networkName}/UUPS.json`) - // TODO: make deploys folder read only. - if (hasPreviousDeploys) { - const deployments = await this.call('fileManager', 'readFile', `.deploys/upgradeable-contracts/${networkName}/UUPS.json`) - const parsedDeployments = JSON.parse(deployments) - const proxyDeployment = parsedDeployments.deployments[proxyAddress] + async saveDeployedContractStorageLayout(contractObject, proxyAddress, networkInfo) { + const {contractName, implementationAddress} = contractObject + const networkName = networkInfo.name === 'custom' ? networkInfo.name + '-' + networkInfo.id : networkInfo.name + const hasPreviousDeploys = await this.call('fileManager', 'exists', `.deploys/upgradeable-contracts/${networkName}/UUPS.json`) + // TODO: make deploys folder read only. + if (hasPreviousDeploys) { + const deployments = await this.call('fileManager', 'readFile', `.deploys/upgradeable-contracts/${networkName}/UUPS.json`) + const parsedDeployments = JSON.parse(deployments) + const proxyDeployment = parsedDeployments.deployments[proxyAddress] - if (proxyDeployment) { - const oldImplementationAddress = proxyDeployment.implementationAddress - const hasPreviousBuild = await this.call('fileManager', 'exists', `.deploys/upgradeable-contracts/${networkName}/solc-${oldImplementationAddress}.json`) + if (proxyDeployment) { + const oldImplementationAddress = proxyDeployment.implementationAddress + const hasPreviousBuild = await this.call('fileManager', 'exists', `.deploys/upgradeable-contracts/${networkName}/solc-${oldImplementationAddress}.json`) - if (hasPreviousBuild) await this.call('fileManager', 'remove', `.deploys/upgradeable-contracts/${networkName}/solc-${oldImplementationAddress}.json`) - } - parsedDeployments.deployments[proxyAddress] = { - date: new Date().toISOString(), - contractName: contractName, - fork: networkInfo.currentFork, - implementationAddress: implementationAddress, - solcOutput: contractObject.compiler.data, - solcInput: contractObject.compiler.source - } - await this.call('fileManager', 'writeFile', `.deploys/upgradeable-contracts/${networkName}/solc-${implementationAddress}.json`, JSON.stringify({ - solcInput: contractObject.compiler.source, - solcOutput: contractObject.compiler.data - }, null, 2)) - await this.call('fileManager', 'writeFile', `.deploys/upgradeable-contracts/${networkName}/UUPS.json`, JSON.stringify(parsedDeployments, null, 2)) - } else { - await this.call('fileManager', 'writeFile', `.deploys/upgradeable-contracts/${networkName}/solc-${implementationAddress}.json`, JSON.stringify({ - solcInput: contractObject.compiler.source, - solcOutput: contractObject.compiler.data - }, null, 2)) - await this.call('fileManager', 'writeFile', `.deploys/upgradeable-contracts/${networkName}/UUPS.json`, JSON.stringify({ - id: networkInfo.id, - network: networkInfo.name, - deployments: { - [proxyAddress]: { - date: new Date().toISOString(), - contractName: contractName, - fork: networkInfo.currentFork, - implementationAddress: implementationAddress - } - } - }, null, 2)) + if (hasPreviousBuild) await this.call('fileManager', 'remove', `.deploys/upgradeable-contracts/${networkName}/solc-${oldImplementationAddress}.json`) } + parsedDeployments.deployments[proxyAddress] = { + date: new Date().toISOString(), + contractName: contractName, + fork: networkInfo.currentFork, + implementationAddress: implementationAddress, + solcOutput: contractObject.compiler.data, + solcInput: contractObject.compiler.source + } + await this.call( + 'fileManager', + 'writeFile', + `.deploys/upgradeable-contracts/${networkName}/solc-${implementationAddress}.json`, + JSON.stringify( + { + solcInput: contractObject.compiler.source, + solcOutput: contractObject.compiler.data + }, + null, + 2 + ) + ) + await this.call('fileManager', 'writeFile', `.deploys/upgradeable-contracts/${networkName}/UUPS.json`, JSON.stringify(parsedDeployments, null, 2)) + } else { + await this.call( + 'fileManager', + 'writeFile', + `.deploys/upgradeable-contracts/${networkName}/solc-${implementationAddress}.json`, + JSON.stringify( + { + solcInput: contractObject.compiler.source, + solcOutput: contractObject.compiler.data + }, + null, + 2 + ) + ) + await this.call( + 'fileManager', + 'writeFile', + `.deploys/upgradeable-contracts/${networkName}/UUPS.json`, + JSON.stringify( + { + id: networkInfo.id, + network: networkInfo.name, + deployments: { + [proxyAddress]: { + date: new Date().toISOString(), + contractName: contractName, + fork: networkInfo.currentFork, + implementationAddress: implementationAddress + } + } + }, + null, + 2 + ) + ) + } } - async getEncodedFunctionHex (args, funABI) { + async getEncodedFunctionHex(args, funABI) { return new Promise((resolve, reject) => { txFormat.encodeFunctionCall(args, funABI, (error, data) => { if (error) return reject(error) @@ -369,7 +426,7 @@ export class Blockchain extends Plugin { }) } - async getEncodedParams (args, funABI) { + async getEncodedParams(args, funABI) { return new Promise((resolve, reject) => { txFormat.encodeParams(args, funABI, (error, encodedParams) => { if (error) return reject(error) @@ -378,27 +435,25 @@ export class Blockchain extends Plugin { }) } - createContract (selectedContract, data, continueCb, promptCb, confirmationCb, finalCb) { + createContract(selectedContract, data, continueCb, promptCb, confirmationCb, finalCb) { if (data) { data.contractName = selectedContract.name data.linkReferences = selectedContract.bytecodeLinkReferences data.contractABI = selectedContract.abi } - this.runTx({ data: data, useCall: false }, confirmationCb, continueCb, promptCb, - (error, txResult, address) => { - if (error) { - return finalCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) - } - if (txResult.receipt.status === false || txResult.receipt.status === '0x0' || txResult.receipt.status === 0) { - return finalCb(`creation of ${selectedContract.name} errored: transaction execution failed`) - } - finalCb(null, selectedContract, address) + this.runTx({data: data, useCall: false}, confirmationCb, continueCb, promptCb, (error, txResult, address) => { + if (error) { + return finalCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) } - ) + if (txResult.receipt.status === false || txResult.receipt.status === '0x0' || txResult.receipt.status === 0) { + return finalCb(`creation of ${selectedContract.name} errored: transaction execution failed`) + } + finalCb(null, selectedContract, address) + }) } - determineGasPrice (cb) { + determineGasPrice(cb) { this.getCurrentProvider().getGasPrice((error, gasPrice) => { const warnMessage = ' Please fix this issue before sending any transaction. ' if (error) { @@ -413,29 +468,29 @@ export class Blockchain extends Plugin { }) } - getInputs (funABI) { + getInputs(funABI) { if (!funABI.inputs) { return '' } return txHelper.inputParametersDeclarationToString(funABI.inputs) } - fromWei (value, doTypeConversion, unit) { + fromWei(value, doTypeConversion, unit) { if (doTypeConversion) { return Web3.utils.fromWei(typeConversion.toInt(value), unit || 'ether') } return Web3.utils.fromWei(value.toString(10), unit || 'ether') } - toWei (value, unit) { + toWei(value, unit) { return Web3.utils.toWei(value, unit || 'gwei') } - calculateFee (gas, gasPrice, unit?) { + calculateFee(gas, gasPrice, unit?) { return Web3.utils.toBN(gas).mul(Web3.utils.toBN(Web3.utils.toWei(gasPrice.toString(10) as string, unit || 'gwei'))) } - determineGasFees (tx) { + determineGasFees(tx) { const determineGasFeesCb = (gasPrice, cb) => { let txFeeText, priceStatus // TODO: this try catch feels like an anti pattern, can/should be @@ -454,19 +509,19 @@ export class Blockchain extends Plugin { return determineGasFeesCb } - changeExecutionContext (context, confirmCb, infoCb, cb) { + changeExecutionContext(context, confirmCb, infoCb, cb) { return this.executionContext.executionContextChange(context, null, confirmCb, infoCb, cb) } - detectNetwork (cb) { + detectNetwork(cb) { return this.executionContext.detectNetwork(cb) } - getProvider () { + getProvider() { return this.executionContext.getProvider() } - getInjectedWeb3Address () { + getInjectedWeb3Address() { return this.executionContext.getSelectedAddress() } @@ -474,29 +529,29 @@ export class Blockchain extends Plugin { * return the fork name applied to the current envionment * @return {String} - fork name */ - getCurrentFork () { + getCurrentFork() { return this.executionContext.getCurrentFork() } - isWeb3Provider () { + isWeb3Provider() { const isVM = this.executionContext.isVM() const isInjected = this.getProvider() === 'injected' - return (!isVM && !isInjected) + return !isVM && !isInjected } - isInjectedWeb3 () { + isInjectedWeb3() { return this.getProvider() === 'injected' } - signMessage (message, account, passphrase, cb) { + signMessage(message, account, passphrase, cb) { this.getCurrentProvider().signMessage(message, account, passphrase, cb) } - web3VM () { + web3VM() { return (this.providers.vm as VMProvider).web3 } - web3 () { + web3() { // @todo(https://github.com/ethereum/remix-project/issues/431) const isVM = this.executionContext.isVM() if (isVM) { @@ -505,7 +560,7 @@ export class Blockchain extends Plugin { return this.executionContext.web3() } - getTxListener (opts) { + getTxListener(opts) { opts.event = { // udapp: this.udapp.event udapp: this.event @@ -514,85 +569,101 @@ export class Blockchain extends Plugin { return txlistener } - runOrCallContractMethod (contractName, contractAbi, funABI, contract, value, address, callType, lookupOnly, logMsg, logCallback, outputCb, confirmationCb, continueCb, promptCb) { + runOrCallContractMethod(contractName, contractAbi, funABI, contract, value, address, callType, lookupOnly, logMsg, logCallback, outputCb, confirmationCb, continueCb, promptCb) { // contractsDetails is used to resolve libraries - txFormat.buildData(contractName, contractAbi, {}, false, funABI, callType, (error, data) => { - if (error) { - return logCallback(`${logMsg} errored: ${error.message ? error.message : error}`) - } - if (!lookupOnly) { - logCallback(`${logMsg} pending ... `) - } else { - logCallback(`${logMsg}`) - } - if (funABI.type === 'fallback') data.dataHex = value - - if (data) { - data.contractName = contractName - data.contractABI = contractAbi - data.contract = contract - } - const useCall = funABI.stateMutability === 'view' || funABI.stateMutability === 'pure' - this.runTx({ to: address, data, useCall }, confirmationCb, continueCb, promptCb, (error, txResult, _address, returnValue) => { + txFormat.buildData( + contractName, + contractAbi, + {}, + false, + funABI, + callType, + (error, data) => { if (error) { return logCallback(`${logMsg} errored: ${error.message ? error.message : error}`) } - if (lookupOnly) { - outputCb(returnValue) + if (!lookupOnly) { + logCallback(`${logMsg} pending ... `) + } else { + logCallback(`${logMsg}`) } - }) - }, - (msg) => { - logCallback(msg) - }, - (data, runTxCallback) => { - // called for libraries deployment - this.runTx(data, confirmationCb, runTxCallback, promptCb, () => { /* Do nothing. */ }) - }) + if (funABI.type === 'fallback') data.dataHex = value + + if (data) { + data.contractName = contractName + data.contractABI = contractAbi + data.contract = contract + } + const useCall = funABI.stateMutability === 'view' || funABI.stateMutability === 'pure' + this.runTx({to: address, data, useCall}, confirmationCb, continueCb, promptCb, (error, txResult, _address, returnValue) => { + if (error) { + return logCallback(`${logMsg} errored: ${error.message ? error.message : error}`) + } + if (lookupOnly) { + outputCb(returnValue) + } + }) + }, + (msg) => { + logCallback(msg) + }, + (data, runTxCallback) => { + // called for libraries deployment + this.runTx(data, confirmationCb, runTxCallback, promptCb, () => { + /* Do nothing. */ + }) + } + ) } - context () { - return (this.executionContext.isVM() ? 'memory' : 'blockchain') + context() { + return this.executionContext.isVM() ? 'memory' : 'blockchain' } // NOTE: the config is only needed because exectuionContext.init does - async resetAndInit (config: Config, transactionContextAPI: TransactionContextAPI) { + async resetAndInit(config: Config, transactionContextAPI: TransactionContextAPI) { this.transactionContextAPI = transactionContextAPI this.executionContext.init(config) this.executionContext.stopListenOnLastBlock() this.executionContext.listenOnLastBlock() } - addProvider (provider) { + addProvider(provider) { this.executionContext.addProvider(provider) } - removeProvider (name) { + removeProvider(name) { this.executionContext.removeProvider(name) } // TODO : event should be triggered by Udapp instead of TxListener /** Listen on New Transaction. (Cannot be done inside constructor because txlistener doesn't exist yet) */ - startListening (txlistener) { + startListening(txlistener) { txlistener.event.register('newTransaction', (tx, receipt) => { this.events.emit('newTransaction', tx, receipt) }) } - async resetEnvironment () { + async resetEnvironment() { await this.getCurrentProvider().resetEnvironment() // TODO: most params here can be refactored away in txRunner - const web3Runner = new TxRunnerWeb3({ - config: this.config, - detectNetwork: (cb) => { - this.executionContext.detectNetwork(cb) + const web3Runner = new TxRunnerWeb3( + { + config: this.config, + detectNetwork: (cb) => { + this.executionContext.detectNetwork(cb) + }, + isVM: () => { + return this.executionContext.isVM() + }, + personalMode: () => { + return this.getProvider() === 'web3' ? this.config.get('settings/personal-mode') : false + } }, - isVM: () => { return this.executionContext.isVM() }, - personalMode: () => { - return this.getProvider() === 'web3' ? this.config.get('settings/personal-mode') : false - } - }, _ => this.executionContext.web3(), _ => this.executionContext.currentblockGasLimit()) - + (_) => this.executionContext.web3(), + (_) => this.executionContext.currentblockGasLimit() + ) + web3Runner.event.register('transactionBroadcasted', (txhash) => { this.executionContext.detectNetwork((error, network) => { if (error || !network) return @@ -600,10 +671,13 @@ export class Blockchain extends Plugin { const viewEtherScanLink = etherScanLink(network.name, txhash) if (viewEtherScanLink) { - this.call('terminal', 'logHtml', - ( - view on etherscan - )) + this.call( + 'terminal', + 'logHtml', + + view on etherscan + + ) } }) }) @@ -614,23 +688,23 @@ export class Blockchain extends Plugin { * Create a VM Account * @param {{privateKey: string, balance: string}} newAccount The new account to create */ - createVMAccount (newAccount) { + createVMAccount(newAccount) { if (!this.executionContext.isVM()) { throw new Error('plugin API does not allow creating a new account through web3 connection. Only vm mode is allowed') } return (this.providers.vm as VMProvider).createVMAccount(newAccount) } - newAccount (_password, passwordPromptCb, cb) { + newAccount(_password, passwordPromptCb, cb) { return this.getCurrentProvider().newAccount(passwordPromptCb, cb) } /** Get the balance of an address, and convert wei to ether */ - getBalanceInEther (address) { + getBalanceInEther(address) { return this.getCurrentProvider().getBalanceInEther(address) } - pendingTransactionsCount () { + pendingTransactionsCount() { return Object.keys(this.txRunner.pendingTxs).length } @@ -638,7 +712,7 @@ export class Blockchain extends Plugin { return await this.web3().eth.getCode(address) } - async getTransactionReceipt (hash) { + async getTransactionReceipt(hash) { return await this.web3().eth.getTransactionReceipt(hash) } @@ -648,7 +722,7 @@ export class Blockchain extends Plugin { * * @param {Object} tx - transaction. */ - sendTransaction (tx: Transaction) { + sendTransaction(tx: Transaction) { return new Promise((resolve, reject) => { this.executionContext.detectNetwork((error, network) => { if (error) return reject(error) @@ -658,17 +732,26 @@ export class Blockchain extends Plugin { this.txRunner.rawRun( tx, - (network, tx, gasEstimation, continueTxExecution, cancelCb) => { continueTxExecution() }, - (error, continueTxExecution, cancelCb) => { if (error) { reject(error) } else { continueTxExecution() } }, - (okCb, cancelCb) => { okCb() }, + (network, tx, gasEstimation, continueTxExecution, cancelCb) => { + continueTxExecution() + }, + (error, continueTxExecution, cancelCb) => { + if (error) { + reject(error) + } else { + continueTxExecution() + } + }, + (okCb, cancelCb) => { + okCb() + }, async (error, result) => { if (error) return reject(error) try { if (this.executionContext.isVM()) { const execResult = await this.web3().eth.getExecutionResultFromSimulator(result.transactionHash) resolve(resultToRemixTx(result, execResult)) - } else - resolve(resultToRemixTx(result)) + } else resolve(resultToRemixTx(result)) } catch (e) { reject(e) } @@ -678,7 +761,7 @@ export class Blockchain extends Plugin { }) } - async runTx (args, confirmationCb, continueCb, promptCb, cb) { + async runTx(args, confirmationCb, continueCb, promptCb, cb) { const getGasLimit = () => { return new Promise((resolve, reject) => { if (this.transactionContextAPI.getGasLimit) { @@ -712,7 +795,10 @@ export class Blockchain extends Plugin { if (this.transactionContextAPI.getAddress) { return this.transactionContextAPI.getAddress(function (err, address) { if (err) return reject(err) - if (!address) return reject('"from" is not defined. Please make sure an account is selected. If you are using a public node, it is likely that no account will be provided. In that case, add the public node to your injected provider (type Metamask) and use injected provider in Remix.') + if (!address) + return reject( + '"from" is not defined. Please make sure an account is selected. If you are using a public node, it is likely that no account will be provided. In that case, add the public node to your injected provider (type Metamask) and use injected provider in Remix.' + ) return resolve(address) }) } @@ -743,46 +829,67 @@ export class Blockchain extends Plugin { return } - const tx = { to: args.to, data: args.data.dataHex, useCall: args.useCall, from: fromAddress, value: value, gasLimit: gasLimit, timestamp: args.data.timestamp } - const payLoad = { funAbi: args.data.funAbi, funArgs: args.data.funArgs, contractBytecode: args.data.contractBytecode, contractName: args.data.contractName, contractABI: args.data.contractABI, linkReferences: args.data.linkReferences } + const tx = { + to: args.to, + data: args.data.dataHex, + useCall: args.useCall, + from: fromAddress, + value: value, + gasLimit: gasLimit, + timestamp: args.data.timestamp + } + const payLoad = { + funAbi: args.data.funAbi, + funArgs: args.data.funArgs, + contractBytecode: args.data.contractBytecode, + contractName: args.data.contractName, + contractABI: args.data.contractABI, + linkReferences: args.data.linkReferences + } if (!tx.timestamp) tx.timestamp = Date.now() const timestamp = tx.timestamp this._triggerEvent('initiatingTransaction', [timestamp, tx, payLoad]) try { - this.txRunner.rawRun(tx, confirmationCb, continueCb, promptCb, - async (error, result) => { - if (error) { - if (typeof (error) !== 'string') { - if (error.message) error = error.message - else { - try { error = 'error: ' + JSON.stringify(error) } catch (e) { console.log(e) } + this.txRunner.rawRun(tx, confirmationCb, continueCb, promptCb, async (error, result) => { + if (error) { + if (typeof error !== 'string') { + if (error.message) error = error.message + else { + try { + error = 'error: ' + JSON.stringify(error) + } catch (e) { + console.log(e) } } - return reject(error) } - - const isVM = this.executionContext.isVM() - if (isVM && tx.useCall) { - try { - result.transactionHash = await this.web3().eth.getHashFromTagBySimulator(timestamp) - } catch (e) { - console.log('unable to retrieve back the "call" hash', e) - } - } - const eventName = (tx.useCall ? 'callExecuted' : 'transactionExecuted') + return reject(error) + } - this._triggerEvent(eventName, [error, tx.from, tx.to, tx.data, tx.useCall, result, timestamp, payLoad]) - return resolve({ result, tx }) + const isVM = this.executionContext.isVM() + if (isVM && tx.useCall) { + try { + result.transactionHash = await this.web3().eth.getHashFromTagBySimulator(timestamp) + } catch (e) { + console.log('unable to retrieve back the "call" hash', e) + } } - ) + const eventName = tx.useCall ? 'callExecuted' : 'transactionExecuted' + + this._triggerEvent(eventName, [error, tx.from, tx.to, tx.data, tx.useCall, result, timestamp, payLoad]) + return resolve({result, tx}) + }) } catch (err) { let error = err - if (error && (typeof (error) !== 'string')) { + if (error && typeof error !== 'string') { if (error.message) error = error.message else { - try { error = 'error: ' + JSON.stringify(error) } catch (e) { console.log(e) } + try { + error = 'error: ' + JSON.stringify(error) + } catch (e) { + console.log(e) + } } } return reject(error) @@ -807,49 +914,64 @@ export class Blockchain extends Plugin { const hhlogs = await this.web3().eth.getHHLogsForTx(txResult.transactionHash) if (hhlogs && hhlogs.length) { - const finalLogs =
console.log:
- { - hhlogs.map((log) => { - let formattedLog - // Hardhat implements the same formatting options that can be found in Node.js' console.log, - // which in turn uses util.format: https://nodejs.org/dist/latest-v12.x/docs/api/util.html#util_util_format_format_args - // For example: console.log("Name: %s, Age: %d", remix, 6) will log 'Name: remix, Age: 6' - // We check first arg to determine if 'util.format' is needed - if (typeof log[0] === 'string' && (log[0].includes('%s') || log[0].includes('%d'))) { - formattedLog = format(log[0], ...log.slice(1)) - } else { - formattedLog = log.join(' ') - } - return
{formattedLog}
- })} -
+ const finalLogs = ( +
+
+ console.log: +
+ {hhlogs.map((log) => { + let formattedLog + // Hardhat implements the same formatting options that can be found in Node.js' console.log, + // which in turn uses util.format: https://nodejs.org/dist/latest-v12.x/docs/api/util.html#util_util_format_format_args + // For example: console.log("Name: %s, Age: %d", remix, 6) will log 'Name: remix, Age: 6' + // We check first arg to determine if 'util.format' is needed + if (typeof log[0] === 'string' && (log[0].includes('%s') || log[0].includes('%d'))) { + formattedLog = format(log[0], ...log.slice(1)) + } else { + formattedLog = log.join(' ') + } + return
{formattedLog}
+ })} +
+ ) _paq.push(['trackEvent', 'udapp', 'hardhat', 'console.log']) this.call('terminal', 'logHtml', finalLogs) } execResult = await this.web3().eth.getExecutionResultFromSimulator(txResult.transactionHash) if (execResult) { // if it's not the VM, we don't have return value. We only have the transaction, and it does not contain the return value. - returnValue = execResult ? toBuffer(execResult.returnValue) : toBuffer(addHexPrefix(txResult.result) || '0x0000000000000000000000000000000000000000000000000000000000000000') + returnValue = execResult + ? toBuffer(execResult.returnValue) + : toBuffer(addHexPrefix(txResult.result) || '0x0000000000000000000000000000000000000000000000000000000000000000') const compiledContracts = await this.call('compilerArtefacts', 'getAllContractDatas') - const vmError = txExecution.checkVMError(execResult, compiledContracts) + const vmError = txExecution.checkError({ errorMessage: execResult.exceptionError ? execResult.exceptionError.error : '', errorData: execResult.returnValue }, compiledContracts) if (vmError.error) { return cb(vmError.message) } } } - if (!isVM && tx && tx.useCall) { returnValue = toBuffer(addHexPrefix(txResult.result)) } - + let address = null if (txResult && txResult.receipt) { address = txResult.receipt.contractAddress } - + cb(null, txResult, address, returnValue) } catch (error) { - cb(error) + if (this.isInjectedWeb3()) { + let errorObj = error.replace('Returned error: ', '') + errorObj = JSON.parse(errorObj) + if (errorObj.errorData) { + const compiledContracts = await this.call('compilerArtefacts', 'getAllContractDatas') + const injectedError = txExecution.checkError({ errorMessage: errorObj.error, errorData: errorObj.errorData }, compiledContracts) + cb(injectedError.message) + } else + cb(error) + } else + cb(error) } } } diff --git a/apps/remix-ide/src/blockchain/helper.ts b/apps/remix-ide/src/blockchain/helper.ts index 5fde384369..7df7546d20 100644 --- a/apps/remix-ide/src/blockchain/helper.ts +++ b/apps/remix-ide/src/blockchain/helper.ts @@ -1,14 +1,14 @@ const transactionDetailsLinks = { - Main: 'https://www.etherscan.io/tx/', - Rinkeby: 'https://rinkeby.etherscan.io/tx/', - Ropsten: 'https://ropsten.etherscan.io/tx/', - Kovan: 'https://kovan.etherscan.io/tx/', - Goerli: 'https://goerli.etherscan.io/tx/', - Sepolia: 'https://sepolia.etherscan.io/tx/' - } + Main: 'https://www.etherscan.io/tx/', + Rinkeby: 'https://rinkeby.etherscan.io/tx/', + Ropsten: 'https://ropsten.etherscan.io/tx/', + Kovan: 'https://kovan.etherscan.io/tx/', + Goerli: 'https://goerli.etherscan.io/tx/', + Sepolia: 'https://sepolia.etherscan.io/tx/' +} - export function etherScanLink (network: string, hash: string): string { - if (transactionDetailsLinks[network]) { - return transactionDetailsLinks[network] + hash - } - } \ No newline at end of file +export function etherScanLink (network: string, hash: string): string { + if (transactionDetailsLinks[network]) { + return transactionDetailsLinks[network] + hash + } +} \ No newline at end of file diff --git a/apps/remix-ide/src/blockchain/providers/injected.ts b/apps/remix-ide/src/blockchain/providers/injected.ts index 557ea32896..bc6ab49e7f 100644 --- a/apps/remix-ide/src/blockchain/providers/injected.ts +++ b/apps/remix-ide/src/blockchain/providers/injected.ts @@ -20,7 +20,7 @@ export class InjectedProvider { } async resetEnvironment () { - /* Do nothing. */ + /* Do nothing. */ } async getBalanceInEther (address) { diff --git a/apps/remix-ide/src/blockchain/providers/node.ts b/apps/remix-ide/src/blockchain/providers/node.ts index fbe0159c19..65116b4923 100644 --- a/apps/remix-ide/src/blockchain/providers/node.ts +++ b/apps/remix-ide/src/blockchain/providers/node.ts @@ -30,7 +30,7 @@ export class NodeProvider { } async resetEnvironment () { - /* Do nothing. */ + /* Do nothing. */ } async getBalanceInEther (address) { diff --git a/apps/remix-ide/src/blockchain/providers/vm.ts b/apps/remix-ide/src/blockchain/providers/vm.ts index 958eb9f6d4..4234e42616 100644 --- a/apps/remix-ide/src/blockchain/providers/vm.ts +++ b/apps/remix-ide/src/blockchain/providers/vm.ts @@ -59,12 +59,12 @@ export class VMProvider { reject(new Error(msg.data.error)) } } else if (msg.data.cmd === 'newAccountResult') { - if (this.newAccountCallback[msg.data.stamp]) { - this.newAccountCallback[msg.data.stamp](msg.data.error, msg.data.result) - delete this.newAccountCallback[msg.data.stamp] + if (this.newAccountCallback[msg.data.stamp]) { + this.newAccountCallback[msg.data.stamp](msg.data.error, msg.data.result) + delete this.newAccountCallback[msg.data.stamp] + } } - } - }) + }) this.worker.postMessage({ cmd: 'init', fork: this.executionContext.getCurrentFork(), nodeUrl: provider?.options['nodeUrl'], blockNumber: provider?.options['blockNumber']}) }) } diff --git a/apps/remix-ide/src/blockchain/providers/worker-vm.ts b/apps/remix-ide/src/blockchain/providers/worker-vm.ts index b261cda864..64a8d0255b 100644 --- a/apps/remix-ide/src/blockchain/providers/worker-vm.ts +++ b/apps/remix-ide/src/blockchain/providers/worker-vm.ts @@ -4,74 +4,74 @@ let provider: Provider = null self.onmessage = (e: MessageEvent) => { const data = e.data switch (data.cmd) { - case 'init': - { - provider = new Provider({ fork: data.fork, nodeUrl: data.nodeUrl, blockNumber: data.blockNumber }) - provider.init().then(() => { - self.postMessage({ - cmd: 'initiateResult', - stamp: data.stamp - }) - }).catch((error) => { + case 'init': + { + provider = new Provider({ fork: data.fork, nodeUrl: data.nodeUrl, blockNumber: data.blockNumber }) + provider.init().then(() => { + self.postMessage({ + cmd: 'initiateResult', + stamp: data.stamp + }) + }).catch((error) => { + self.postMessage({ + cmd: 'initiateResult', + error, + stamp: data.stamp + }) + }) + break + } + case 'sendAsync': + { + if (provider) { + provider.sendAsync(data.query, (error, result) => { self.postMessage({ - cmd: 'initiateResult', + cmd: 'sendAsyncResult', error, + result, stamp: data.stamp }) }) - break + } else { + self.postMessage({ + cmd: 'sendAsyncResult', + error: 'Provider not instantiated', + result: null, + stamp: data.stamp + }) } - case 'sendAsync': - { - if (provider) { - provider.sendAsync(data.query, (error, result) => { - self.postMessage({ - cmd: 'sendAsyncResult', - error, - result, - stamp: data.stamp - }) - }) - } else { - self.postMessage({ - cmd: 'sendAsyncResult', - error: 'Provider not instantiated', - result: null, - stamp: data.stamp - }) - } - break + break + } + case 'addAccount': + { + if (provider) { + provider.Accounts._addAccount(data.privateKey, data.balance) } - case 'addAccount': - { - if (provider) { - provider.Accounts._addAccount(data.privateKey, data.balance) - } - break + break + } + case 'newAccount': + { + if (provider) { + provider.Accounts.newAccount((error, address: string) => { + if (error) { + self.postMessage({ + cmd: 'newAccountResult', + error, + stamp: data.stamp + }) + } else { + self.postMessage({ + cmd: 'newAccountResult', + result: address, + stamp: data.stamp + }) + } + }) } - case 'newAccount': - { - if (provider) { - provider.Accounts.newAccount((error, address: string) => { - if (error) { - self.postMessage({ - cmd: 'newAccountResult', - error, - stamp: data.stamp - }) - } else { - self.postMessage({ - cmd: 'newAccountResult', - result: address, - stamp: data.stamp - }) - } - }) - } - break - } + break + } } } diff --git a/apps/remix-ide/src/index.tsx b/apps/remix-ide/src/index.tsx index 37bee1f5aa..94d143eb1e 100644 --- a/apps/remix-ide/src/index.tsx +++ b/apps/remix-ide/src/index.tsx @@ -1,19 +1,18 @@ // eslint-disable-next-line no-use-before-define import React from 'react' -import { render } from 'react-dom' +import {render} from 'react-dom' import './index.css' -import { ThemeModule } from './app/tabs/theme-module' -import { Preload } from './app/components/preload' +import {ThemeModule} from './app/tabs/theme-module' +import {Preload} from './app/components/preload' import Config from './config' import Registry from './app/state/registry' -import { Storage } from '@remix-project/remix-lib' - -(async function () { +import {Storage} from '@remix-project/remix-lib' +;(async function () { try { const configStorage = new Storage('config-v0.8:') - const config = new Config(configStorage); - Registry.getInstance().put({ api: config, name: 'config' }) - } catch (e) { } + const config = new Config(configStorage) + Registry.getInstance().put({api: config, name: 'config'}) + } catch (e) {} const theme = new ThemeModule() theme.initTheme() @@ -25,5 +24,3 @@ import { Storage } from '@remix-project/remix-lib' ) })() - - diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 49e5d23ece..c64a92be85 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -1,19 +1,81 @@ -import { PluginManager } from '@remixproject/engine' -import { EventEmitter } from 'events' -import { QueryParams } from '@remix-project/remix-lib' -import { IframePlugin } from '@remixproject/engine-web' +import {PluginManager} from '@remixproject/engine' +import {EventEmitter} from 'events' +import {QueryParams} from '@remix-project/remix-lib' +import {IframePlugin} from '@remixproject/engine-web' const isElectron = require('is-electron') -const _paq = window._paq = window._paq || [] +const _paq = (window._paq = window._paq || []) // requiredModule removes the plugin from the plugin manager list on UI -let requiredModules = [ // services + layout views + system views - 'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'locale', - 'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', - 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout', - 'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy', - 'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected', 'injected-trustwallet', 'injected-optimism-provider', 'injected-arbitrum-one-provider', 'vm-custom-fork', 'vm-goerli-fork', 'vm-mainnet-fork', 'vm-sepolia-fork', 'vm-merge', 'vm-london', 'vm-berlin', +let requiredModules = [ + // services + layout views + system views + 'manager', + 'config', + 'compilerArtefacts', + 'compilerMetadata', + 'contextualListener', + 'editor', + 'offsetToLineColumnConverter', + 'network', + 'theme', + 'locale', + 'fileManager', + 'contentImport', + 'blockchain', + 'web3Provider', + 'scriptRunner', + 'fetchAndCompile', + 'mainPanel', + 'hiddenPanel', + 'sidePanel', + 'menuicons', + 'filePanel', + 'terminal', + 'settings', + 'pluginManager', + 'tabs', + 'udapp', + 'dGitProvider', + 'solidity', + 'solidity-logic', + 'gistHandler', + 'layout', + 'notification', + 'permissionhandler', + 'walkthrough', + 'storage', + 'restorebackupzip', + 'link-libraries', + 'deploy-libraries', + 'openzeppelin-proxy', + 'hardhat-provider', + 'ganache-provider', + 'foundry-provider', + 'basic-http-provider', + 'injected', + 'injected-trustwallet', + 'injected-optimism-provider', + 'injected-arbitrum-one-provider', + 'injected-ephemery-testnet-provider', + 'injected-skale-chaos-testnet-provider', + 'vm-custom-fork', + 'vm-goerli-fork', + 'vm-mainnet-fork', + 'vm-sepolia-fork', + 'vm-merge', + 'vm-london', + 'vm-berlin', 'vm-shanghai', - 'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser', 'codeFormatter', 'solidityumlgen', 'contractflattener', 'solidity-script'] + 'compileAndRun', + 'search', + 'recorder', + 'fileDecorator', + 'codeParser', + 'codeFormatter', + 'solidityumlgen', + 'contractflattener', + 'solidity-script', + 'openaigpt' +] if (isElectron()) { requiredModules = [...requiredModules, 'fs', 'electronTemplates', 'isogit', 'remix-templates', 'electronconfig'] @@ -23,19 +85,41 @@ if (isElectron()) { // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither'] -const loadLocalPlugins = ["doc-gen", "doc-viewer", "etherscan", "vyper", 'solhint', 'walletconnect'] +const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'etherscan', 'vyper', 'solhint', 'walletconnect', 'circuit-compiler'] const sensitiveCalls = { - 'fileManager': ['writeFile', 'copyFile', 'rename', 'copyDir'], - 'contentImport': ['resolveAndSave'], - 'web3Provider': ['sendAsync'], + fileManager: ['writeFile', 'copyFile', 'rename', 'copyDir'], + contentImport: ['resolveAndSave'], + web3Provider: ['sendAsync'] } export function isNative(name) { // nativePlugin allows to bypass the permission request - const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'solidity-logic', 'solidityStaticAnalysis', 'solidityUnitTesting', - 'layout', 'notification', 'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected-optimism-provider', - 'tabs', 'injected-arbitrum-one-provider', 'injected', 'doc-gen', 'doc-viewer'] + const nativePlugins = [ + 'vyper', + 'workshops', + 'debugger', + 'remixd', + 'menuicons', + 'solidity', + 'solidity-logic', + 'solidityStaticAnalysis', + 'solidityUnitTesting', + 'layout', + 'notification', + 'hardhat-provider', + 'ganache-provider', + 'foundry-provider', + 'basic-http-provider', + 'injected-optimism-provider', + 'tabs', + 'injected-arbitrum-one-provider', + 'injected-skale-chaos-testnet-provider', + 'injected-ephemery-testnet-provider', + 'injected', + 'doc-gen', + 'doc-viewer' + ] return nativePlugins.includes(name) || requiredModules.includes(name) } @@ -50,9 +134,7 @@ export function isNative(name) { * @returns {boolean} */ export function canActivate(from, to) { - return ['ethdoc'].includes(from.name) || - isNative(from.name) || - (to && from && from.canActivate && from.canActivate.includes(to.name)) + return ['ethdoc'].includes(from.name) || isNative(from.name) || (to && from && from.canActivate && from.canActivate.includes(to.name)) } export class RemixAppManager extends PluginManager { @@ -78,10 +160,7 @@ export class RemixAppManager extends PluginManager { async deactivatePlugin(name) { const profile = await this.getProfile(name) - const [to, from] = [ - profile, - await this.getProfile(this.requestFrom) - ] + const [to, from] = [profile, await this.getProfile(this.requestFrom)] if (this.canDeactivatePlugin(from, to)) { if (profile.methods.includes('deactivate')) { try { @@ -110,7 +189,10 @@ export class RemixAppManager extends PluginManager { } onPluginActivated(plugin) { - this.pluginLoader.set(plugin, this.actives.filter((plugin) => !this.isDependent(plugin))) + this.pluginLoader.set( + plugin, + this.actives.filter((plugin) => !this.isDependent(plugin)) + ) this.event.emit('activate', plugin) this.emit('activate', plugin) if (!requiredModules.includes(plugin.name)) _paq.push(['trackEvent', 'pluginManager', 'activate', plugin.name]) @@ -127,7 +209,10 @@ export class RemixAppManager extends PluginManager { } onPluginDeactivated(plugin) { - this.pluginLoader.set(plugin, this.actives.filter((plugin) => !this.isDependent(plugin))) + this.pluginLoader.set( + plugin, + this.actives.filter((plugin) => !this.isDependent(plugin)) + ) this.event.emit('deactivate', plugin) _paq.push(['trackEvent', 'pluginManager', 'deactivate', plugin.name]) } @@ -148,7 +233,7 @@ export class RemixAppManager extends PluginManager { plugins = await res.json() plugins = plugins.filter((plugin) => { if (plugin.targets && Array.isArray(plugin.targets) && plugin.targets.length > 0) { - return (plugin.targets.includes('remix')) + return plugin.targets.includes('remix') } return true }) @@ -256,13 +341,17 @@ class PluginLoader { const saved = actives.filter((name) => !this.donotAutoReload.includes(name)) localStorage.setItem('workspace', JSON.stringify(saved)) }, - get: () => { return JSON.parse(localStorage.getItem('workspace')) } + get: () => { + return JSON.parse(localStorage.getItem('workspace')) + } } this.loaders.queryParams = { - set: () => { /* Do nothing. */ }, + set: () => { + /* Do nothing. */ + }, get: () => { - const { activate } = queryParams.get() + const {activate} = queryParams.get() if (!activate) return [] return activate.split(',') } diff --git a/apps/remix-ide/src/remixEngine.js b/apps/remix-ide/src/remixEngine.js index 6f1b159781..d7264b2c0e 100644 --- a/apps/remix-ide/src/remixEngine.js +++ b/apps/remix-ide/src/remixEngine.js @@ -22,6 +22,7 @@ export class RemixEngine extends Engine { if (name === 'udapp') return { queueTimeout: 60000 * 4 } if (name === 'fs') return { queueTimeout: 60000 * 4 } if (name === 'isogit') return { queueTimeout: 60000 * 4 } + if (name === 'circuit-compiler') return { queueTimeout: 60000 * 4 } return { queueTimeout: 10000 } } diff --git a/apps/remix-ide/team-best-practices.md b/apps/remix-ide/team-best-practices.md index 8777280bc5..946078fe47 100644 --- a/apps/remix-ide/team-best-practices.md +++ b/apps/remix-ide/team-best-practices.md @@ -1,11 +1,11 @@ # Team best practices -This document aims to address contibutors best practices of the following repositories: +This document aims to address contributors best practices of the following repositories: - remix-ide https://github.com/ethereum/remix-project - remix-plugin https://github.com/ethereum/remix-plugin -This document is not in its final version, **a team meeting which aim to address new/old best practices, feedback, workflows, all kind of issues related to how the team work together occurs every 2 weeks.** +This document is not in its final version, **a team meeting which aims to address new/old best practices, feedback, workflows, all kind of issues related to how the team work together occurs every 2 weeks.** This document link to other specialised best practices (like coding best practices). Related links: @@ -32,22 +32,22 @@ Related links: - Daily standup (1pm CET - 11am GMT) for taking care of the current issues. - - A regular standup - each Tuesday (3pm CET - 1pm GMT) - which aim to + - A regular standup - each Tuesday (3pm CET - 1pm GMT) - which aims to - Update every contributor on what others are doing. - Update the prioritised issues / PRs list. - Address little issues (possibly related to the current ongoing milestone). - High level demo, explanation about specific points of the codebase or Ethereum related things. - - A milestone standup - scheduled before the beginning of each milestone, roughly on a monthly basis - which aim to define what will be included in the **next milestone** and who will work on what. This standup also help to set a clear long term vision. + - A milestone standup - scheduled before the beginning of each milestone, roughly on a monthly basis - which aims to define what will be included in the **next milestone** and who will work on what. This standup also help to set a clear long term vision. - - A retrospective standup - after each releases - which aim to talk about **best practices in general**: what is good, what is bad, how we can improve workflows. + - A retrospective standup - after each releases - which aims to talk about **best practices in general**: what is good, what is bad, how we can improve workflows. - - A tour standup - Just after a release or whenever it is needed - which aim to demo, **explain in details** features, bug fixes or any part of the codebase. + - A tour standup - Just after a release or whenever it is needed - which aims to demo, **explain in details** features, bug fixes or any part of the codebase. ### 2) Group meetings: - - When a story / bug fix is divided in parts, there should be a kickstart meeting with all the developers involved, so that all the devs have an good overview / understanding on: + - When a story / bug fix is divided in parts, there should be a kickstart meeting with all the developers involved, so that all the devs have a good overview / understanding on: - How the story fits into the Ethereum tech. - How the backend (if any) works / will work (could be a smart contract). - How the frontend works / will work. @@ -72,7 +72,7 @@ Before starting coding, we should ensure all devs / contributors are aware of: - Prioritised list of PRs / issues are tracked in a GitHub Project, Remix IDE issues are managed by a prioritized backlog. - Every story can be executed by a single developer or a group of 2 or more developers (depending on the size and complexity) -- Each dev should take the part he/she feels the most confortable with. +- Each dev should take the part he/she feels the most comfortable with. - Later progress and discussion is updated directly on the issue or pull request (github). - When a developer or team decides on the story they want to work on (at the start of milestone for instance), they assign themselves to the issue. - Documentation update should be done together with the story, or an issue with the label "documentation" has to be created. @@ -195,21 +195,21 @@ Before starting coding, we should ensure all devs / contributors are aware of: ### release process: - We release an `x.0.0` if there's a fundamental change in our UX design, which means users will need to readapt the way they use the app - - after a week finishes, we publish/release a new version as **remix-beta.ethereum.org** and inform users so early adopters can test. after another week, when then next finished work is released as **remix-beta.ethereum.org**, the previous one becomes **remix.ethereum.org** and all users can start using it + - after a week finishes, we publish/release a new version as **remix-beta.ethereum.org** and inform users so early adopters can test. after another week, when the next finished work is released as **remix-beta.ethereum.org**, the previous one becomes **remix.ethereum.org** and all users can start using it - a bot to automatically notify users about upcoming features on all channels whenever **remix-beta.ethereum.org** is updated - in case it's a major version increase - this announcement should be specially marked so ppl can check early instead of being confronted with drastic changes when **remix.ethereum.org** updates ### maintenance: - Setting up a "bug" time where we each take a bug for which: - - We feel confortable to deal with + - We feel comfortable to deal with or - - We don't feel confortable but interested in fixing it - that will need the help of another dev + - We don't feel comfortable but interested in fixing it - that will need the help of another dev ### documentation: - We set up a special day where we address all the necessary documentation work in a team effort. - Change to markdown or gitbook ### support: - Remix channel - we rotate and each day one or two are responsible for support (It would also be important to know for those of us who are contracted, how this can be billed.). If they don't know the answer they ping team member who they think could answer. That team member checks the support chat that day only if she/he is mentioned. - - We should have a FAQ where basic answer are written down so we can drop the link regularly in the channel + - We should have a FAQ where basic answers are written down so we can drop the link regularly in the channel - People should be pointed to the appropriate `best practice.md` files by team members ### code best practices: diff --git a/apps/remix-ide/webpack.config.js b/apps/remix-ide/webpack.config.js index 97eab162e2..a7cade0f2a 100644 --- a/apps/remix-ide/webpack.config.js +++ b/apps/remix-ide/webpack.config.js @@ -1,11 +1,11 @@ -const { composePlugins, withNx } = require('@nrwl/webpack') -const { withReact } = require('@nrwl/react') +const {composePlugins, withNx} = require('@nrwl/webpack') +const {withReact} = require('@nrwl/react') const webpack = require('webpack') -const CopyPlugin = require("copy-webpack-plugin") +const CopyPlugin = require('copy-webpack-plugin') const version = require('../../package.json').version const fs = require('fs') -const TerserPlugin = require("terser-webpack-plugin") -const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') const axios = require('axios') const versionData = { @@ -50,30 +50,30 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { // add fallback for node modules config.resolve.fallback = { ...config.resolve.fallback, - "crypto": require.resolve("crypto-browserify"), - "stream": require.resolve("stream-browserify"), - "path": require.resolve("path-browserify"), - "http": require.resolve("stream-http"), - "https": require.resolve("https-browserify"), - "constants": require.resolve("constants-browserify"), - "os": false, //require.resolve("os-browserify/browser"), - "timers": false, // require.resolve("timers-browserify"), - "zlib": require.resolve("browserify-zlib"), - "fs": false, - "module": false, - "tls": false, - "net": false, - "readline": false, - "child_process": false, - "buffer": require.resolve("buffer/"), - "vm": require.resolve('vm-browserify'), + crypto: require.resolve('crypto-browserify'), + stream: require.resolve('stream-browserify'), + path: require.resolve('path-browserify'), + http: require.resolve('stream-http'), + https: require.resolve('https-browserify'), + constants: require.resolve('constants-browserify'), + os: false, //require.resolve("os-browserify/browser"), + timers: false, // require.resolve("timers-browserify"), + zlib: require.resolve('browserify-zlib'), + 'assert/strict': require.resolve('assert/'), + fs: false, + module: false, + tls: false, + net: false, + readline: false, + child_process: false, + buffer: require.resolve('buffer/'), + vm: require.resolve('vm-browserify') } - // add externals config.externals = { ...config.externals, - solc: 'solc', + solc: 'solc' } // add public path @@ -87,12 +87,14 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { config.output.filename = `[name].${versionData.version}.${versionData.timestamp}.js` config.output.chunkFilename = `[name].${versionData.version}.${versionData.timestamp}.js` - // add copy & provide plugin config.plugins.push( new CopyPlugin({ patterns: [ - { from: '../../node_modules/monaco-editor/min/vs', to: 'assets/js/monaco-editor/min/vs' }, + { + from: '../../node_modules/monaco-editor/min/vs', + to: 'assets/js/monaco-editor/min/vs' + }, ...copyPatterns ].filter(Boolean) }), @@ -107,8 +109,8 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { // souce-map loader config.module.rules.push({ test: /\.js$/, - use: ["source-map-loader"], - enforce: "pre" + use: ['source-map-loader'], + enforce: 'pre' }) config.ignoreWarnings = [/Failed to parse source map/, /require function/] // ignore source-map-loader warnings & AST warnings @@ -122,13 +124,13 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { compress: false, mangle: false, format: { - comments: false, - }, + comments: false + } }, - extractComments: false, + extractComments: false }), - new CssMinimizerPlugin(), - ]; + new CssMinimizerPlugin() + ] // minify code if(process.env.NX_DESKTOP_FROM_DIST) @@ -143,7 +145,7 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { }); class CopyFileAfterBuild { - apply(compiler) { + apply(compiler) { const onEnd = async () => { try { console.log('runnning CopyFileAfterBuild') @@ -151,17 +153,15 @@ class CopyFileAfterBuild { // This is needed because by default the etherscan resources are served from the /plugins/etherscan/ folder, // but the raw-loader try to access the resources from the root folder. const files = fs.readdirSync('./dist/apps/etherscan') - files.forEach(file => { + files.forEach((file) => { if (file.includes('plugin-etherscan')) { fs.copyFileSync('./dist/apps/etherscan/' + file, './dist/apps/remix-ide/' + file) - } + } }) } catch (e) { console.error('running CopyFileAfterBuild failed with error: ' + e.message) - } + } } - compiler.hooks.afterEmit.tapPromise('FileManagerPlugin', onEnd); + compiler.hooks.afterEmit.tapPromise('FileManagerPlugin', onEnd) } } - - diff --git a/apps/solhint/src/app/App.tsx b/apps/solhint/src/app/App.tsx index ac1eae48b3..929d6c6658 100644 --- a/apps/solhint/src/app/App.tsx +++ b/apps/solhint/src/app/App.tsx @@ -1,8 +1,8 @@ -import React, { useEffect, useState } from "react"; -import { SolHint } from "./SolhintPluginClient"; +import React, {useEffect, useState} from 'react' +import {SolHint} from './SolhintPluginClient' -const client = new SolHint(); +const client = new SolHint() export default function App() { - return <>; + return <> } diff --git a/apps/solhint/webpack.config.js b/apps/solhint/webpack.config.js index 2e3893c15c..a52cc43bf1 100644 --- a/apps/solhint/webpack.config.js +++ b/apps/solhint/webpack.config.js @@ -1,18 +1,18 @@ -const { composePlugins, withNx } = require('@nrwl/webpack') -const { withReact } = require('@nrwl/react') +const {composePlugins, withNx} = require('@nrwl/webpack') +const {withReact} = require('@nrwl/react') const webpack = require('webpack') -const TerserPlugin = require("terser-webpack-plugin") -const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') // Nx plugins for webpack. module.exports = composePlugins(withNx(), withReact(), (config) => { // Update the webpack config as needed here. config.resolve.fallback = { ...config.resolve.fallback, - "path": false, - "os": false, - "fs": false, - "module": false, + path: false, + os: false, + fs: false, + module: false } // add public path @@ -23,18 +23,18 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], url: ['url', 'URL'], - process: 'process/browser', + process: 'process/browser' }), new webpack.DefinePlugin({ - "BROWSER": true, - }), + BROWSER: true + }) ) // souce-map loader config.module.rules.push({ test: /\.js$/, - use: ["source-map-loader"], - enforce: "pre" + use: ['source-map-loader'], + enforce: 'pre' }) config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings @@ -48,13 +48,13 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { compress: false, mangle: false, format: { - comments: false, - }, + comments: false + } }, - extractComments: false, + extractComments: false }), - new CssMinimizerPlugin(), - ]; + new CssMinimizerPlugin() + ] - return config; + return config }) diff --git a/apps/solhint/yarn.lock b/apps/solhint/yarn.lock index 6d16a269b3..b9a9bf3e3a 100644 --- a/apps/solhint/yarn.lock +++ b/apps/solhint/yarn.lock @@ -415,9 +415,9 @@ resolve-from@^4.0.0: integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== slice-ansi@^4.0.0: version "4.0.0" diff --git a/apps/solidity-compiler/src/app/app.tsx b/apps/solidity-compiler/src/app/app.tsx index 7115b1509a..e9c636ac3d 100644 --- a/apps/solidity-compiler/src/app/app.tsx +++ b/apps/solidity-compiler/src/app/app.tsx @@ -1,9 +1,9 @@ /* eslint-disable no-use-before-define */ import React from 'react' -import { SolidityCompiler } from '@remix-ui/solidity-compiler' // eslint-disable-line +import {SolidityCompiler} from '@remix-ui/solidity-compiler' // eslint-disable-line -import { CompilerClientApi } from './compiler' +import {CompilerClientApi} from './compiler' const remix = new CompilerClientApi() diff --git a/apps/solidity-compiler/webpack.config.js b/apps/solidity-compiler/webpack.config.js index e19684ca91..23aef38cff 100644 --- a/apps/solidity-compiler/webpack.config.js +++ b/apps/solidity-compiler/webpack.config.js @@ -1,10 +1,10 @@ -const { composePlugins, withNx } = require('@nrwl/webpack') -const { withReact } = require('@nrwl/react') +const {composePlugins, withNx} = require('@nrwl/webpack') +const {withReact} = require('@nrwl/react') const webpack = require('webpack') const version = require('../../package.json').version const fs = require('fs') -const TerserPlugin = require("terser-webpack-plugin") -const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') const versionData = { version: version, @@ -22,56 +22,52 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { // add fallback for node modules config.resolve.fallback = { ...config.resolve.fallback, - "crypto": require.resolve("crypto-browserify"), - "stream": require.resolve("stream-browserify"), - "path": require.resolve("path-browserify"), - "http": require.resolve("stream-http"), - "https": require.resolve("https-browserify"), - "constants": require.resolve("constants-browserify"), - "os": false, //require.resolve("os-browserify/browser"), - "timers": false, // require.resolve("timers-browserify"), - "zlib": require.resolve("browserify-zlib"), - "fs": false, - "module": false, - "tls": false, - "net": false, - "readline": false, - "child_process": false, - "buffer": require.resolve("buffer/"), - "vm": require.resolve('vm-browserify'), + crypto: require.resolve('crypto-browserify'), + stream: require.resolve('stream-browserify'), + path: require.resolve('path-browserify'), + http: require.resolve('stream-http'), + https: require.resolve('https-browserify'), + constants: require.resolve('constants-browserify'), + os: false, //require.resolve("os-browserify/browser"), + timers: false, // require.resolve("timers-browserify"), + zlib: require.resolve('browserify-zlib'), + fs: false, + module: false, + tls: false, + net: false, + readline: false, + child_process: false, + buffer: require.resolve('buffer/'), + vm: require.resolve('vm-browserify') } - // add externals config.externals = { ...config.externals, - solc: 'solc', + solc: 'solc' } // add public path config.output.publicPath = '/' - - // add copy & provide plugin config.plugins.push( new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], url: ['url', 'URL'], - process: 'process/browser', + process: 'process/browser' }) ) // souce-map loader config.module.rules.push({ test: /\.js$/, - use: ["source-map-loader"], - enforce: "pre" + use: ['source-map-loader'], + enforce: 'pre' }) config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings - // set minimizer config.optimization.minimizer = [ new TerserPlugin({ @@ -81,17 +77,17 @@ module.exports = composePlugins(withNx(), withReact(), (config) => { compress: false, mangle: false, format: { - comments: false, - }, + comments: false + } }, - extractComments: false, + extractComments: false }), - new CssMinimizerPlugin(), - ]; + new CssMinimizerPlugin() + ] config.watchOptions = { ignored: /node_modules/ } - return config; -}); + return config +}) diff --git a/apps/vyper/src/app/app.tsx b/apps/vyper/src/app/app.tsx index e5f9d80159..aa4ab4093f 100644 --- a/apps/vyper/src/app/app.tsx +++ b/apps/vyper/src/app/app.tsx @@ -1,7 +1,7 @@ -import React, { useState, useEffect } from 'react' +import React, {useState, useEffect} from 'react' -import { VyperCompilationOutput, remixClient } from './utils' -import { CompilationResult } from '@remixproject/plugin-api' +import {VyperCompilationOutput, remixClient} from './utils' +import {CompilationResult} from '@remixproject/plugin-api' // Components import CompilerButton from './components/CompilerButton' @@ -38,7 +38,7 @@ const App: React.FC = () => { async function start() { try { await remixClient.loaded() - remixClient.onFileChange(name => setContract(name)) + remixClient.onFileChange((name) => setContract(name)) remixClient.onNoFileSelected(() => setContract('')) } catch (err) { console.log(err) @@ -53,17 +53,15 @@ const App: React.FC = () => { /** Update the environment state value */ function setEnvironment(environment: 'local' | 'remote') { - setState({ ...state, environment }) + setState({...state, environment}) } function setLocalUrl(url: string) { - setState({ ...state, localUrl: url }) + setState({...state, localUrl: url}) } function compilerUrl() { - return state.environment === 'remote' - ? 'https://vyper.remixproject.org/compile' - : state.localUrl + return state.environment === 'remote' ? 'https://vyper.remixproject.org/compile' : state.localUrl } return ( @@ -73,12 +71,8 @@ const App: React.FC = () => { Vyper logo

yper Compiler

- - + +
@@ -87,12 +81,7 @@ const App: React.FC = () => { Clone Vyper examples repository
- + Remote Compiler v0.2.16 @@ -100,20 +89,10 @@ const App: React.FC = () => { Local Compiler - +
- - setOutput({ ...output, [name]: update }) - } - /> + setOutput({...output, [name]: update})} />
diff --git a/apps/vyper/src/app/components/CompilerButton.tsx b/apps/vyper/src/app/components/CompilerButton.tsx index fba082575b..9cb3ac630a 100644 --- a/apps/vyper/src/app/components/CompilerButton.tsx +++ b/apps/vyper/src/app/components/CompilerButton.tsx @@ -1,22 +1,14 @@ import React from 'react' -import { - isVyper, - compile, - toStandardOutput, - VyperCompilationOutput, - isCompilationError, - remixClient -} from '../utils' +import {isVyper, compile, toStandardOutput, VyperCompilationOutput, isCompilationError, remixClient} from '../utils' import Button from 'react-bootstrap/Button' interface Props { compilerUrl: string - contract?: string, + contract?: string setOutput: (name: string, output: VyperCompilationOutput) => void } -function CompilerButton({ contract, setOutput, compilerUrl }: Props) { - +function CompilerButton({contract, setOutput, compilerUrl}: Props) { if (!contract || !contract) { return } @@ -33,9 +25,9 @@ function CompilerButton({ contract, setOutput, compilerUrl }: Props) { try { _contract = await remixClient.getContract() } catch (e: any) { - setOutput('', { status: 'failed', message: e.message}) + setOutput('', {status: 'failed', message: e.message}) return - } + } remixClient.changeStatus({ key: 'loading', type: 'info', @@ -45,17 +37,17 @@ function CompilerButton({ contract, setOutput, compilerUrl }: Props) { try { output = await compile(compilerUrl, _contract) } catch (e: any) { - setOutput(_contract.name, { status: 'failed', message: e.message}) + setOutput(_contract.name, {status: 'failed', message: e.message}) return - } + } setOutput(_contract.name, output) // ERROR if (isCompilationError(output)) { const line = output.line if (line) { const lineColumnPos = { - start: { line: line - 1, column: 10 }, - end: { line: line - 1, column: 10 } + start: {line: line - 1, column: 10}, + end: {line: line - 1, column: 10} } remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4') } else { @@ -70,12 +62,12 @@ function CompilerButton({ contract, setOutput, compilerUrl }: Props) { if (message && message.split('\n\n').length > 0) { try { message = message.split('\n\n')[message.split('\n\n').length - 1] - } catch (e) {} + } catch (e) {} } if (location.length > 0) { const lineColumnPos = { - start: { line: parseInt(location[0]) - 1, column: 10 }, - end: { line: parseInt(location[0]) - 1, column: 10 } + start: {line: parseInt(location[0]) - 1, column: 10}, + end: {line: parseInt(location[0]) - 1, column: 10} } remixClient.highlight(lineColumnPos as any, _contract.name, message) } @@ -105,7 +97,7 @@ function CompilerButton({ contract, setOutput, compilerUrl }: Props) { return ( ) } diff --git a/apps/vyper/src/app/components/LocalUrl.tsx b/apps/vyper/src/app/components/LocalUrl.tsx index 47acde9dad..58f4b3d3c7 100644 --- a/apps/vyper/src/app/components/LocalUrl.tsx +++ b/apps/vyper/src/app/components/LocalUrl.tsx @@ -3,12 +3,11 @@ import Form from 'react-bootstrap/Form' interface Props { url: string - setUrl: (url: string) => void, + setUrl: (url: string) => void environment: 'remote' | 'local' } -function LocalUrlInput({ url, setUrl, environment }: Props) { - +function LocalUrlInput({url, setUrl, environment}: Props) { if (environment === 'remote') { return <> } @@ -20,17 +19,13 @@ function LocalUrlInput({ url, setUrl, environment }: Props) { return (
- Currently we support vyper version > 0.2.16 + {'Currently we support vyper version > 0.2.16'} Local Compiler Url - - - + +
) } -export default LocalUrlInput; +export default LocalUrlInput diff --git a/apps/vyper/src/app/components/VyperResult.tsx b/apps/vyper/src/app/components/VyperResult.tsx index 44ccba7b7f..016271805b 100644 --- a/apps/vyper/src/app/components/VyperResult.tsx +++ b/apps/vyper/src/app/components/VyperResult.tsx @@ -1,43 +1,45 @@ -import React, { useState } from 'react'; -import { - VyperCompilationResult, - VyperCompilationOutput, - isCompilationError, -} from '../utils'; +import React, {useState} from 'react' +import {VyperCompilationResult, VyperCompilationOutput, isCompilationError} from '../utils' import Tabs from 'react-bootstrap/Tabs' import Tab from 'react-bootstrap/Tab' -import Button from 'react-bootstrap/Button'; +import Button from 'react-bootstrap/Button' import JSONTree from 'react-json-view' -import { CopyToClipboard } from '@remix-ui/clipboard' +import {CopyToClipboard} from '@remix-ui/clipboard' interface VyperResultProps { - output?: VyperCompilationOutput; + output?: VyperCompilationOutput } export type ExampleContract = { - name: string, + name: string address: string } -function VyperResult({ output }: VyperResultProps) { - const [ active, setActive ] = useState('abi') +function VyperResult({output}: VyperResultProps) { + const [active, setActive] = useState('abi') - if (!output) return ( - -
-

No contract compiled yet.

-
- ) + if (!output) + return ( +
+

No contract compiled yet.

+
+ ) if (isCompilationError(output)) { return (
-
{output.message}
+
+          {output.message}
+        
) } @@ -46,30 +48,38 @@ function VyperResult({ output }: VyperResultProps) { setActive(key)}> JSON.stringify(output.abi)}> - + output.bytecode}> - + output.bytecode_runtime}> - + output.ir}> - + - ); + ) } -export default VyperResult; \ No newline at end of file +export default VyperResult diff --git a/apps/vyper/src/app/components/WarnRemote.tsx b/apps/vyper/src/app/components/WarnRemote.tsx index 107ab13335..ee0d4b9422 100644 --- a/apps/vyper/src/app/components/WarnRemote.tsx +++ b/apps/vyper/src/app/components/WarnRemote.tsx @@ -4,8 +4,7 @@ interface Props { environment: 'remote' | 'local' } -function WarnRemoteLabel({ environment }: Props) { - +function WarnRemoteLabel({environment}: Props) { if (environment === 'local') { return <> } @@ -15,4 +14,4 @@ function WarnRemoteLabel({ environment }: Props) { ) } -export default WarnRemoteLabel; \ No newline at end of file +export default WarnRemoteLabel diff --git a/apps/vyper/src/app/utils/compiler.tsx b/apps/vyper/src/app/utils/compiler.tsx index 0b65c65a1a..d1312322c4 100644 --- a/apps/vyper/src/app/utils/compiler.tsx +++ b/apps/vyper/src/app/utils/compiler.tsx @@ -1,16 +1,16 @@ -import { CompilationResult, ABIDescription } from "@remixproject/plugin-api"; +import {CompilationResult, ABIDescription} from '@remixproject/plugin-api' export interface Contract { - name: string; - content: string; + name: string + content: string } export interface VyperCompilationResult { - status: 'success', - bytecode: string, - bytecode_runtime: string, - abi: ABIDescription[], - ir: string, + status: 'success' + bytecode: string + bytecode_runtime: string + abi: ABIDescription[] + ir: string method_identifiers: { [method: string]: string } @@ -32,7 +32,7 @@ export function isCompilationError(output: VyperCompilationOutput): output is Vy /** * Compile the a contract - * @param url The url of the compiler + * @param url The url of the compiler * @param contract The name and content of the contract */ export async function compile(url: string, contract: Contract): Promise { @@ -45,8 +45,8 @@ export async function compile(url: string, contract: Contract): Promise>(this); + private client = createClient>(this) loaded() { return this.client.onload() @@ -42,10 +42,19 @@ export class RemixClient extends PluginClient { // @ts-ignore this.call('notification', 'toast', 'cloning Vyper repository...') await this.call('manager', 'activatePlugin', 'dGitProvider') - // @ts-ignore - await this.call('dGitProvider', 'clone', { url: 'https://github.com/vyperlang/vyper', token: null }, 'vyper-lang') - // @ts-ignore - this.call('notification', 'toast', 'Vyper repository cloned, the workspace Vyper has been created.') + await this.call( + 'dGitProvider', + 'clone', + {url: 'https://github.com/vyperlang/vyper', token: null}, + // @ts-ignore + 'vyper-lang' + ) + this.call( + // @ts-ignore + 'notification', + 'toast', + 'Vyper repository cloned, the workspace Vyper has been created.' + ) } catch (e) { // @ts-ignore this.call('notification', 'toast', e.message) @@ -54,7 +63,7 @@ export class RemixClient extends PluginClient { /** Update the status of the plugin in remix */ changeStatus(status: Status) { - this.client.emit('statusChanged', status); + this.client.emit('statusChanged', status) } /** Highlight a part of the editor */ @@ -94,15 +103,15 @@ export class RemixClient extends PluginClient { const content = await this.client.call('fileManager', 'getFile', name) return { name, - content, + content } } /** Emit an event to Remix with compilation result */ compilationFinish(title: string, content: string, data: CompilationResult) { - this.client.emit('compilationFinished', title, content, 'vyper', data); + this.client.emit('compilationFinished', title, content, 'vyper', data) } } export const remixClient = new RemixClient() -// export const RemixClientContext = React.createContext(new RemixClient()) \ No newline at end of file +// export const RemixClientContext = React.createContext(new RemixClient()) diff --git a/apps/vyper/src/main.tsx b/apps/vyper/src/main.tsx index 353ad43f6d..5f17c9ab24 100644 --- a/apps/vyper/src/main.tsx +++ b/apps/vyper/src/main.tsx @@ -1,7 +1,11 @@ -import { StrictMode } from 'react'; -import * as ReactDOM from 'react-dom'; +import {StrictMode} from 'react' +import * as ReactDOM from 'react-dom' +import App from './app/app' -import App from './app/app'; - -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( + + + , + document.getElementById('root') +) diff --git a/apps/vyper/webpack.config.js b/apps/vyper/webpack.config.js index 9feb0dc08d..4bc648f1db 100644 --- a/apps/vyper/webpack.config.js +++ b/apps/vyper/webpack.config.js @@ -1,8 +1,7 @@ -const { composePlugins, withNx } = require('@nrwl/webpack') +const {composePlugins, withNx} = require('@nrwl/webpack') const webpack = require('webpack') -const TerserPlugin = require("terser-webpack-plugin") -const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") - +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') // Nx plugins for webpack. module.exports = composePlugins(withNx(), (config) => { @@ -12,56 +11,52 @@ module.exports = composePlugins(withNx(), (config) => { // add fallback for node modules config.resolve.fallback = { ...config.resolve.fallback, - "crypto": require.resolve("crypto-browserify"), - "stream": require.resolve("stream-browserify"), - "path": require.resolve("path-browserify"), - "http": require.resolve("stream-http"), - "https": require.resolve("https-browserify"), - "constants": require.resolve("constants-browserify"), - "os": false, //require.resolve("os-browserify/browser"), - "timers": false, // require.resolve("timers-browserify"), - "zlib": require.resolve("browserify-zlib"), - "fs": false, - "module": false, - "tls": false, - "net": false, - "readline": false, - "child_process": false, - "buffer": require.resolve("buffer/"), - "vm": require.resolve('vm-browserify'), + crypto: require.resolve('crypto-browserify'), + stream: require.resolve('stream-browserify'), + path: require.resolve('path-browserify'), + http: require.resolve('stream-http'), + https: require.resolve('https-browserify'), + constants: require.resolve('constants-browserify'), + os: false, //require.resolve("os-browserify/browser"), + timers: false, // require.resolve("timers-browserify"), + zlib: require.resolve('browserify-zlib'), + fs: false, + module: false, + tls: false, + net: false, + readline: false, + child_process: false, + buffer: require.resolve('buffer/'), + vm: require.resolve('vm-browserify') } - // add externals config.externals = { ...config.externals, - solc: 'solc', + solc: 'solc' } // add public path config.output.publicPath = '/' - - // add copy & provide plugin config.plugins.push( new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], url: ['url', 'URL'], - process: 'process/browser', + process: 'process/browser' }) ) // souce-map loader config.module.rules.push({ test: /\.js$/, - use: ["source-map-loader"], - enforce: "pre" + use: ['source-map-loader'], + enforce: 'pre' }) config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings - // set minimizer config.optimization.minimizer = [ new TerserPlugin({ @@ -71,17 +66,17 @@ module.exports = composePlugins(withNx(), (config) => { compress: false, mangle: false, format: { - comments: false, - }, + comments: false + } }, - extractComments: false, + extractComments: false }), - new CssMinimizerPlugin(), - ]; + new CssMinimizerPlugin() + ] config.watchOptions = { ignored: /node_modules/ } - return config; -}); + return config +}) diff --git a/apps/walletconnect/src/app/app.tsx b/apps/walletconnect/src/app/app.tsx index 55bf606b58..3aef77cf81 100644 --- a/apps/walletconnect/src/app/app.tsx +++ b/apps/walletconnect/src/app/app.tsx @@ -1,35 +1,35 @@ -import React, { useEffect, useState } from 'react' +import React, {useEffect, useState} from 'react' import '../css/app.css' import '@fortawesome/fontawesome-free/css/all.css' -import type { EthereumClient } from '@web3modal/ethereum' -import { RemixClient } from '../services/RemixClient' -import { WalletConnectUI } from './walletConnectUI' +import type {EthereumClient} from '@web3modal/ethereum' +import {WalletConnectRemixClient} from '../services/WalletConnectRemixClient' +import {WalletConnectUI} from './walletConnectUI' -const remix = new RemixClient() +const remix = new WalletConnectRemixClient() function App() { const [ethereumClient, setEthereumClient] = useState(null) - const [wagmiClient, setWagmiClient] = useState(null) + const [wagmiConfig, setWagmiConfig] = useState(null) const [theme, setTheme] = useState('dark') useEffect(() => { - (async () => { + ;(async () => { await remix.initClient() remix.internalEvents.on('themeChanged', (theme: string) => { setTheme(theme) }) - - setWagmiClient(remix.wagmiClient) + + setWagmiConfig(remix.wagmiConfig) setEthereumClient(remix.ethereumClient) })() }, []) return (
-

WalletConnect

- { ethereumClient && wagmiClient && } +

WalletConnect

+ {ethereumClient && wagmiConfig && }
) } -export default App \ No newline at end of file +export default App diff --git a/apps/walletconnect/src/app/walletConnectUI.tsx b/apps/walletconnect/src/app/walletConnectUI.tsx index a120de4941..38c205000f 100644 --- a/apps/walletconnect/src/app/walletConnectUI.tsx +++ b/apps/walletconnect/src/app/walletConnectUI.tsx @@ -1,17 +1,16 @@ -import { Web3Button, Web3Modal } from "@web3modal/react" -import { WagmiConfig } from "wagmi" -import { PROJECT_ID } from "../services/constant" +import {Web3Button, Web3Modal} from '@web3modal/react' +import {WagmiConfig} from 'wagmi' +import {PROJECT_ID} from '../services/constant' -export function WalletConnectUI ({ ethereumClient, wagmiClient, theme }) { - - return ( -
-
- - - -
- -
- ) +export function WalletConnectUI({ethereumClient, wagmiConfig, theme}) { + return ( +
+
+ + + +
+ +
+ ) } diff --git a/apps/walletconnect/src/main.tsx b/apps/walletconnect/src/main.tsx index b63438d846..818cf01a94 100644 --- a/apps/walletconnect/src/main.tsx +++ b/apps/walletconnect/src/main.tsx @@ -2,7 +2,4 @@ import React from 'react' import ReactDOM from 'react-dom' import App from './app/app' -ReactDOM.render( - , - document.getElementById('root') -) \ No newline at end of file +ReactDOM.render(, document.getElementById('root')) diff --git a/apps/walletconnect/src/services/RemixClient.ts b/apps/walletconnect/src/services/RemixClient.ts deleted file mode 100644 index d884eb775c..0000000000 --- a/apps/walletconnect/src/services/RemixClient.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { PluginClient } from '@remixproject/plugin' -import { createClient } from '@remixproject/plugin-webview' -import { w3mConnectors, w3mProvider } from '@web3modal/ethereum' -import { configureChains, createClient as wagmiCreateClient } from 'wagmi' -import { arbitrum, arbitrumGoerli, mainnet, polygon, polygonMumbai, optimism, optimismGoerli, Chain, goerli, sepolia } from 'wagmi/chains' -import { EthereumClient } from '@web3modal/ethereum' -import EventManager from "events" -import { PROJECT_ID } from './constant' - -export class RemixClient extends PluginClient { - wagmiClient - ethereumClient: EthereumClient - chains: Chain[] - currentChain: number - internalEvents: EventManager - - constructor() { - super() - createClient(this) - this.internalEvents = new EventManager() - this.methods = ["sendAsync", "init", "deactivate"] - this.onload() - } - - onActivation () { - this.subscribeToEvents() - this.call('theme', 'currentTheme').then((theme: any) => { - this.internalEvents.emit('themeChanged', theme.quality.toLowerCase()) - }) - } - - init () { - console.log('initializing walletconnect plugin...') - } - - async initClient () { - try { - this.chains = [arbitrum, arbitrumGoerli, mainnet, polygon, polygonMumbai, optimism, optimismGoerli, goerli, sepolia] - const { provider } = configureChains(this.chains, [w3mProvider({ projectId: PROJECT_ID })]) - - this.wagmiClient = wagmiCreateClient({ - autoConnect: false, - connectors: w3mConnectors({ projectId: PROJECT_ID, version: 2, chains: this.chains }), - provider - }) - this.ethereumClient = new EthereumClient(this.wagmiClient, this.chains) - } catch (e) { - return console.error("Could not get a wallet connection", e) - } - } - - subscribeToEvents () { - this.wagmiClient.subscribe((event) => { - if (event.status === 'connected') { - this.emit('accountsChanged', [event.data.account]) - if (this.currentChain !== event.data.chain.id) { - this.currentChain = event.data.chain.id - this.emit('chainChanged', event.data.chain.id) - } - } else if (event.status === 'disconnected') { - this.emit('accountsChanged', []) - this.emit('chainChanged', 0) - this.currentChain = 0 - } - }) - this.on('theme', 'themeChanged', (theme: any) => { - this.internalEvents.emit('themeChanged', theme.quality) - }) - } - - sendAsync (data: { method: string, params: string, id: string }) { - return new Promise((resolve, reject) => { - if (this.wagmiClient) { - if (this.wagmiClient.data && this.wagmiClient.data.provider && this.wagmiClient.data.provider.sendAsync) { - this.wagmiClient.data.provider.sendAsync(data, (error, message) => { - if (error) return reject(error) - resolve(message) - }) - } else if (this.wagmiClient.data && this.wagmiClient.data.provider && this.wagmiClient.data.provider.jsonRpcFetchFunc) { - if (data.method === 'net_version' || data.method === 'eth_chainId') { - resolve({"jsonrpc": "2.0", "result": this.currentChain, "id": data.id}) - } else { - this.wagmiClient.data.provider.jsonRpcFetchFunc(data.method, data.params).then((message) => { - resolve({"jsonrpc": "2.0", "result": message, "id": data.id}) - }).catch((error) => { - reject(error) - }) - } - } else { - this.wagmiClient.provider.send(data.method, data.params).then((message) => { - resolve({"jsonrpc": "2.0", "result": message, "id": data.id}) - }).catch((error) => { - reject(error) - }) - } - } else { - console.error(`Cannot make ${data.method} request. Remix client is not connect to walletconnect client`) - resolve({"jsonrpc": "2.0", "result": [], "id": data.id}) - } - }) - } - - async deactivate(){ - console.log('deactivating walletconnect plugin...') - await this.ethereumClient.disconnect() - } -} \ No newline at end of file diff --git a/apps/walletconnect/src/services/WalletConnectRemixClient.ts b/apps/walletconnect/src/services/WalletConnectRemixClient.ts new file mode 100644 index 0000000000..6f8b494d00 --- /dev/null +++ b/apps/walletconnect/src/services/WalletConnectRemixClient.ts @@ -0,0 +1,135 @@ +import {PluginClient} from '@remixproject/plugin' +import {createClient} from '@remixproject/plugin-webview' +import {w3mConnectors, w3mProvider} from '@web3modal/ethereum' +import {createConfig, configureChains} from 'wagmi' +import { + arbitrum, + arbitrumGoerli, + mainnet, + polygon, + polygonMumbai, + optimism, + optimismGoerli, + Chain, + goerli, + sepolia +} from 'viem/chains' +import {EthereumClient} from '@web3modal/ethereum' +import EventManager from 'events' +import {PROJECT_ID} from './constant' + +export class WalletConnectRemixClient extends PluginClient { + wagmiConfig + ethereumClient: EthereumClient + chains: Chain[] + currentChain: number + internalEvents: EventManager + + constructor() { + super() + createClient(this) + this.internalEvents = new EventManager() + this.methods = ['sendAsync', 'init', 'deactivate'] + this.onload() + } + + onActivation() { + this.subscribeToEvents() + this.call('theme', 'currentTheme').then((theme: any) => { + this.internalEvents.emit('themeChanged', theme.quality.toLowerCase()) + }) + } + + init() { + console.log('initializing walletconnect plugin...') + } + + async initClient() { + try { + this.chains = [ + mainnet, + arbitrum, + arbitrumGoerli, + polygon, + polygonMumbai, + optimism, + optimismGoerli, + goerli, + sepolia + ] + const {publicClient} = configureChains(this.chains, [ + w3mProvider({projectId: PROJECT_ID}) + ]) + + this.wagmiConfig = createConfig({ + autoConnect: false, + connectors: w3mConnectors({projectId: PROJECT_ID, chains: this.chains}), + publicClient + }) + this.ethereumClient = new EthereumClient(this.wagmiConfig, this.chains) + } catch (e) { + return console.error('Could not get a wallet connection', e) + } + } + + subscribeToEvents() { + this.wagmiConfig.subscribe((event) => { + if (event.status === 'connected') { + this.emit('accountsChanged', [event.data.account]) + if (this.currentChain !== event.data.chain.id) { + this.currentChain = event.data.chain.id + this.emit('chainChanged', event.data.chain.id) + } + } else if (event.status === 'disconnected') { + this.emit('accountsChanged', []) + this.emit('chainChanged', 0) + this.currentChain = 0 + } + }) + this.on('theme', 'themeChanged', (theme: any) => { + this.internalEvents.emit('themeChanged', theme.quality) + }) + } + + async sendAsync(data: {method: string; params: string; id: string}) { + if (this.wagmiConfig.status === 'connected') { + if (data.method === 'eth_accounts') { + return { + jsonrpc: '2.0', + result: [this.wagmiConfig.data.account], + id: data.id + } + } else { + const provider = await this.wagmiConfig.connector.getProvider({ + chainId: this.wagmiConfig.data.chain.id + }) + + if (provider.isMetaMask) { + return new Promise((resolve) => { + provider.sendAsync(data, (err, response) => { + if (err) { + console.error(err) + return resolve({jsonrpc: '2.0', result: [], id: data.id}) + } + return resolve(response) + }) + }) + } else { + const message = await provider.request(data) + + return {jsonrpc: '2.0', result: message, id: data.id} + } + } + } else { + console.error( + `Cannot make ${data.method} request. Remix client is not connected to walletconnect client` + ) + return {jsonrpc: '2.0', result: [], id: data.id} + } + } + + async deactivate() { + console.log('deactivating walletconnect plugin...') + await this.ethereumClient.disconnect() + } +} diff --git a/apps/walletconnect/src/services/provider.ts b/apps/walletconnect/src/services/provider.ts deleted file mode 100644 index 57560fb22b..0000000000 --- a/apps/walletconnect/src/services/provider.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { providers } from 'ethers' - -import type { Chain } from 'wagmi/chains' -import type { ChainProviderFn } from 'wagmi/' - -interface FallbackProviderConfig { - // The Provider - provider: any; - - // The priority to favour this Provider; lower values are used first (higher priority) - priority?: number; - - // Timeout before also triggering the next provider; this does not stop - // this provider and if its result comes back before a quorum is reached - // it will be incorporated into the vote - // - lower values will cause more network traffic but may result in a - // faster result. - stallTimeout?: number; - - // How much this provider contributes to the quorum; sometimes a specific - // provider may be more reliable or trustworthy than others, but usually - // this should be left as the default - weight?: number; -} - -export function customProvider({ - priority, - stallTimeout, - weight, -}: FallbackProviderConfig): ChainProviderFn< - TChain, - providers.Web3Provider, - providers.WebSocketProvider -> { - return function (chain) { - return { - chain: { - ...chain, - } as TChain, - provider: () => { - const provider = new providers.Web3Provider( - window.ethereum, - { - chainId: chain.id, - name: chain.network, - ensAddress: chain.contracts?.ensRegistry?.address, - } - ) - return Object.assign(provider, { priority, stallTimeout, weight }) - } - } - } -} \ No newline at end of file diff --git a/apps/walletconnect/webpack.config.js b/apps/walletconnect/webpack.config.js index 51de9dd815..3a3693c88a 100644 --- a/apps/walletconnect/webpack.config.js +++ b/apps/walletconnect/webpack.config.js @@ -1,7 +1,7 @@ -const { composePlugins, withNx } = require('@nrwl/webpack') +const {composePlugins, withNx} = require('@nrwl/webpack') const webpack = require('webpack') -const TerserPlugin = require("terser-webpack-plugin") -const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') // Nx plugins for webpack. module.exports = composePlugins(withNx(), (config) => { @@ -10,30 +10,29 @@ module.exports = composePlugins(withNx(), (config) => { // add fallback for node modules config.resolve.fallback = { ...config.resolve.fallback, - "crypto": require.resolve("crypto-browserify"), - "stream": require.resolve("stream-browserify"), - "path": require.resolve("path-browserify"), - "http": require.resolve("stream-http"), - "https": require.resolve("https-browserify"), - "constants": require.resolve("constants-browserify"), - "os": false, //require.resolve("os-browserify/browser"), - "timers": false, // require.resolve("timers-browserify"), - "zlib": require.resolve("browserify-zlib"), - "fs": false, - "module": false, - "tls": false, - "net": false, - "readline": false, - "child_process": false, - "buffer": require.resolve("buffer/"), - "vm": require.resolve('vm-browserify'), + crypto: require.resolve('crypto-browserify'), + stream: require.resolve('stream-browserify'), + path: require.resolve('path-browserify'), + http: require.resolve('stream-http'), + https: require.resolve('https-browserify'), + constants: require.resolve('constants-browserify'), + os: false, //require.resolve("os-browserify/browser"), + timers: false, // require.resolve("timers-browserify"), + zlib: require.resolve('browserify-zlib'), + fs: false, + module: false, + tls: false, + net: false, + readline: false, + child_process: false, + buffer: require.resolve('buffer/'), + vm: require.resolve('vm-browserify') } - // add externals config.externals = { ...config.externals, - solc: 'solc', + solc: 'solc' } // add public path @@ -44,27 +43,26 @@ module.exports = composePlugins(withNx(), (config) => { new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], url: ['url', 'URL'], - process: 'process/browser', + process: 'process/browser' }) ) // set the define plugin to load the WALLET_CONNECT_PROJECT_ID config.plugins.push( new webpack.DefinePlugin({ - WALLET_CONNECT_PROJECT_ID: JSON.stringify(process.env.WALLET_CONNECT_PROJECT_ID), + WALLET_CONNECT_PROJECT_ID: JSON.stringify(process.env.WALLET_CONNECT_PROJECT_ID) }) ) // souce-map loader config.module.rules.push({ test: /\.js$/, - use: ["source-map-loader"], - enforce: "pre" + use: ['source-map-loader'], + enforce: 'pre' }) config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings - // set minimizer config.optimization.minimizer = [ new TerserPlugin({ @@ -74,17 +72,17 @@ module.exports = composePlugins(withNx(), (config) => { compress: false, mangle: false, format: { - comments: false, - }, + comments: false + } }, - extractComments: false, + extractComments: false }), - new CssMinimizerPlugin(), - ]; + new CssMinimizerPlugin() + ] config.watchOptions = { ignored: /node_modules/ } - return config; -}); + return config +}) diff --git a/libs/ghaction-helper/package.json b/libs/ghaction-helper/package.json index a621851e7b..bf4fe18c4c 100644 --- a/libs/ghaction-helper/package.json +++ b/libs/ghaction-helper/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/ghaction-helper", - "version": "0.1.9", + "version": "0.1.13", "description": "Solidity Tests GitHub Action Helper", "main": "src/index.js", "scripts": { @@ -19,17 +19,17 @@ }, "homepage": "https://github.com/ethereum/remix-project#readme", "devDependencies": { - "@remix-project/remix-solidity": "^0.5.15", + "@remix-project/remix-solidity": "^0.5.19", "@types/chai": "^4.3.4", "typescript": "^4.9.3" }, "dependencies": { "@ethereum-waffle/chai": "^3.4.4", - "@remix-project/remix-simulator": "^0.2.29", + "@remix-project/remix-simulator": "^0.2.33", "chai": "^4.3.7", "ethers": "^5.7.2", "web3": "^1.5.3" }, "types": "./src/index.d.ts", - "gitHead": "bd494e84f12d18787433f25b7dea264c7b2063f8" + "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220" } \ No newline at end of file diff --git a/libs/ghaction-helper/src/methods.ts b/libs/ghaction-helper/src/methods.ts index 8bea9f5532..b6558f4eb0 100644 --- a/libs/ghaction-helper/src/methods.ts +++ b/libs/ghaction-helper/src/methods.ts @@ -198,7 +198,7 @@ const getContractAt = async (contractNameOrABI: ethers.ContractInterface, addres if (result) { return new ethers.Contract(address, result.abi, signer || provider.getSigner()) } else { - throw new Error('Contract artifacts not found') + throw new Error('Contract artifacts not found') } } else { return new ethers.Contract(address, contractNameOrABI, signer || provider.getSigner()) diff --git a/libs/ghaction-helper/src/signer.ts b/libs/ghaction-helper/src/signer.ts index c6b6cf9d2a..ff5626b566 100644 --- a/libs/ghaction-helper/src/signer.ts +++ b/libs/ghaction-helper/src/signer.ts @@ -2,8 +2,8 @@ import { ethers } from "ethers" export class SignerWithAddress extends ethers.Signer { - address: string - _signer: { + address: string + _signer: { provider: any signTransaction: (transaction: any) => any, signMessage: (message: string) => any, @@ -11,43 +11,43 @@ export class SignerWithAddress extends ethers.Signer { connect: (provider: any) => any, _signTypedData: (...params: any) => any } - provider: any - static async create(signer: any) { - return new SignerWithAddress(await signer.getAddress(), signer) - } - - constructor(address: string, _signer: any) { - super() - this.address = address - this._signer = _signer - this.provider = _signer.provider - } - - async getAddress() { - return this.address - } - - signMessage(message: string){ - return this._signer.signMessage(message) - } - - signTransaction(transaction: any) { - return this._signer.signTransaction(transaction) - } - - sendTransaction(transaction: any) { - return this._signer.sendTransaction(transaction) - } - - connect(provider: any) { - return new SignerWithAddress(this.address, this._signer.connect(provider)) - } - - _signTypedData(...params: any) { - return this._signer._signTypedData(...params) - } - - toJSON() { - return `` - } + provider: any + static async create(signer: any) { + return new SignerWithAddress(await signer.getAddress(), signer) + } + + constructor(address: string, _signer: any) { + super() + this.address = address + this._signer = _signer + this.provider = _signer.provider + } + + async getAddress() { + return this.address + } + + signMessage(message: string){ + return this._signer.signMessage(message) + } + + signTransaction(transaction: any) { + return this._signer.signTransaction(transaction) + } + + sendTransaction(transaction: any) { + return this._signer.sendTransaction(transaction) + } + + connect(provider: any) { + return new SignerWithAddress(this.address, this._signer.connect(provider)) + } + + _signTypedData(...params: any) { + return this._signer._signTypedData(...params) + } + + toJSON() { + return `` + } } \ No newline at end of file diff --git a/libs/remix-analyzer/README.md b/libs/remix-analyzer/README.md index a2cc46d6bd..2cbb7d39d4 100644 --- a/libs/remix-analyzer/README.md +++ b/libs/remix-analyzer/README.md @@ -53,7 +53,7 @@ Details of modules are explained in [official remix-ide documentation](https://r Please feel free to open an issue or a pull request. -In case you want to add some code, do have a look to our contribution guidelnes [here](https://github.com/ethereum/remix-project/blob/master/CONTRIBUTING.md). Reach us on [Gitter](https://gitter.im/ethereum/remix) in case of any queries. +In case you want to add some code, do have a look at our contribution guidelines [here](https://github.com/ethereum/remix-project/blob/master/CONTRIBUTING.md). Reach us on [Gitter](https://gitter.im/ethereum/remix) in case of any queries. ### License MIT © 2018-21 Remix Team diff --git a/libs/remix-analyzer/package.json b/libs/remix-analyzer/package.json index e6cefea828..781a3a3bdc 100644 --- a/libs/remix-analyzer/package.json +++ b/libs/remix-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-analyzer", - "version": "0.5.38", + "version": "0.5.42", "description": "Tool to perform static analysis on Solidity smart contracts", "scripts": { "test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts" @@ -25,8 +25,8 @@ "@ethereumjs/tx": "^4.1.1", "@ethereumjs/util": "^8.0.5", "@ethereumjs/vm": "^6.4.1", - "@remix-project/remix-astwalker": "^0.0.59", - "@remix-project/remix-lib": "^0.5.36", + "@remix-project/remix-astwalker": "^0.0.63", + "@remix-project/remix-lib": "^0.5.40", "async": "^2.6.2", "ethers": "^5.4.2", "ethjs-util": "^0.1.6", @@ -50,6 +50,6 @@ "typescript": "^3.7.5" }, "typings": "src/index.d.ts", - "gitHead": "bd494e84f12d18787433f25b7dea264c7b2063f8", + "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220", "main": "./src/index.js" } \ No newline at end of file diff --git a/libs/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts b/libs/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts index 39ee3faa2d..04193a6afb 100644 --- a/libs/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts +++ b/libs/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts @@ -43,31 +43,31 @@ export default class lowLevelCalls implements AnalyzerModule { let text = '' let morehref = '' switch (item.type) { - case lowLevelCallTypes.CALL: - text = `Use of "call": should be avoided whenever possible. + case lowLevelCallTypes.CALL: + text = `Use of "call": should be avoided whenever possible. It can lead to unexpected behavior if return value is not handled properly. Please use Direct Calls via specifying the called contract's interface.` - morehref = `https://solidity.readthedocs.io/en/${version}/control-structures.html?#external-function-calls` - break - case lowLevelCallTypes.CALLCODE: - text = `Use of "callcode": should be avoided whenever possible. + morehref = `https://solidity.readthedocs.io/en/${version}/control-structures.html?#external-function-calls` + break + case lowLevelCallTypes.CALLCODE: + text = `Use of "callcode": should be avoided whenever possible. External code, that is called can change the state of the calling contract and send ether from the caller's balance. If this is wanted behaviour, use the Solidity library feature if possible.` - morehref = `https://solidity.readthedocs.io/en/${version}/contracts.html#libraries` - break - case lowLevelCallTypes.DELEGATECALL: - text = `Use of "delegatecall": should be avoided whenever possible. + morehref = `https://solidity.readthedocs.io/en/${version}/contracts.html#libraries` + break + case lowLevelCallTypes.DELEGATECALL: + text = `Use of "delegatecall": should be avoided whenever possible. External code, that is called can change the state of the calling contract and send ether from the caller's balance. If this is wanted behaviour, use the Solidity library feature if possible.` - morehref = `https://solidity.readthedocs.io/en/${version}/contracts.html#libraries` - break - case lowLevelCallTypes.SEND: - text = `Use of "send": "send" does not throw an exception when not successful, make sure you deal with the failure case accordingly. + morehref = `https://solidity.readthedocs.io/en/${version}/contracts.html#libraries` + break + case lowLevelCallTypes.SEND: + text = `Use of "send": "send" does not throw an exception when not successful, make sure you deal with the failure case accordingly. Use "transfer" whenever failure of the ether transfer should rollback the whole transaction. Note: if you "send/transfer" ether to a contract the fallback function is called, the callees fallback function is very limited due to the limited amount of gas provided by "send/transfer". No state changes are possible but the callee can log the event or revert the transfer. "send/transfer" is syntactic sugar for a "call" to the fallback function with 2300 gas and a specified ether value.` - morehref = `https://solidity.readthedocs.io/en/${version}/security-considerations.html#sending-and-receiving-ether` - break + morehref = `https://solidity.readthedocs.io/en/${version}/security-considerations.html#sending-and-receiving-ether` + break } return { warning: text, more: morehref, location: item.node.src } }) diff --git a/libs/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts b/libs/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts index 6d258d5909..9818c4a925 100644 --- a/libs/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts +++ b/libs/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts @@ -427,7 +427,7 @@ function getLibraryCallMemberName (funcCall: FunctionCallAstNode): string { * function baz() { * bar(10) => foo.bar(uint) * @func {ASTNode} function call node - * @func {ASTNode} contract defintion + * @func {ASTNode} contract definition * @return {string} full qualified identifier for the function call */ function getFullQualifiedFunctionCallIdent (contract: ContractDefinitionAstNode, func: FunctionCallAstNode): string { @@ -468,8 +468,8 @@ function isStatement (node: any): boolean { // #################### Complex Node Identification /** - * True if function defintion has function body - * @funcNode {ASTNode} function defintion node + * True if function definition has function body + * @funcNode {ASTNode} function definition node * @return {bool} */ function hasFunctionBody (funcNode: FunctionDefinitionAstNode): boolean { @@ -630,7 +630,7 @@ function isStateVariable (name: string, stateVariables: VariableDeclarationAstNo } /** - * True if is function defintion that is flaged as constant + * True if is function definition that is flaged as constant * @node {ASTNode} some AstNode * @return {bool} */ @@ -648,7 +648,7 @@ function isVariableTurnedIntoGetter (varDeclNode: VariableDeclarationAstNode): b } /** - * True if is function defintion has payable modifier + * True if is function definition has payable modifier * @node {ASTNode} some AstNode * @return {bool} */ @@ -743,7 +743,7 @@ function isFullyImplementedContract (node: ContractDefinitionAstNode): boolean { } /** - * True if it is a library contract defintion + * True if it is a library contract definition * @node {ASTNode} some AstNode * @return {bool} */ diff --git a/libs/remix-analyzer/test/analysis/staticAnalysisCommon-test.ts b/libs/remix-analyzer/test/analysis/staticAnalysisCommon-test.ts index f8a1649053..859dfe9758 100644 --- a/libs/remix-analyzer/test/analysis/staticAnalysisCommon-test.ts +++ b/libs/remix-analyzer/test/analysis/staticAnalysisCommon-test.ts @@ -1,10 +1,10 @@ import { default as test} from "tape" import * as common from '../../src/solidity-analyzer/modules/staticAnalysisCommon' const { localCall, thisLocalCall, libCall, externalDirect, superLocal, assignment, abiNamespaceCallNodes, - inlineAssembly, unaryOperation, nowAst, blockTimestamp, stateVariableContractNode, - functionDefinition, requireCall, selfdestruct, storageVariableNodes, dynamicDeleteUnaryOp, - // eslint-disable-next-line @typescript-eslint/no-var-requires - lowlevelCall, parameterFunction, parameterFunctionCall, inheritance, blockHashAccess, contractDefinition, funcDefForComplexParams } = require('./astBlocks') + inlineAssembly, unaryOperation, nowAst, blockTimestamp, stateVariableContractNode, + functionDefinition, requireCall, selfdestruct, storageVariableNodes, dynamicDeleteUnaryOp, + // eslint-disable-next-line @typescript-eslint/no-var-requires + lowlevelCall, parameterFunction, parameterFunctionCall, inheritance, blockHashAccess, contractDefinition, funcDefForComplexParams } = require('./astBlocks') // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -40,11 +40,11 @@ test('staticAnalysisCommon.helpers.buildFunctionSignature', function (t) { 'function (bytes memory) payable returns (bool,bytes memory)', 'check fixed call type') -t.equal(common.lowLevelCallTypes['CALL-0.4'].type, + t.equal(common.lowLevelCallTypes['CALL-0.4'].type, 'function () payable returns (bool)', 'check fixed call type for versions before 0.5.0') -t.equal(common.lowLevelCallTypes.CALLCODE.type, + t.equal(common.lowLevelCallTypes.CALLCODE.type, 'function () payable returns (bool)', 'check fixed callcode type') @@ -56,7 +56,7 @@ t.equal(common.lowLevelCallTypes.CALLCODE.type, 'function (bytes memory) returns (bool,bytes memory)', 'check fixed delegatecall type') -t.equal(common.lowLevelCallTypes['DELEGATECALL-0.4'].type, + t.equal(common.lowLevelCallTypes['DELEGATECALL-0.4'].type, 'function () returns (bool)', 'check fixed delegatecall type for version before 0.5.0') }) @@ -141,18 +141,18 @@ test('staticAnalysisCommon.helpers.expressionTypeDescription', function (t) { test('staticAnalysisCommon.getType', function (t) { t.plan(3) const node = { "argumentTypes": null, - "id": 3, - "name": "a", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 22, - "src": "52:1:0", - "typeDescriptions": + "id": 3, + "name": "a", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 22, + "src": "52:1:0", + "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } - } + } t.ok(common.getType(blockHashAccess) === 'bytes32', 'gettype should work for different nodes') t.ok(common.getType(node) === 'uint256', 'gettype should work for different nodes') t.ok(common.getType(assignment) === 'uint256', 'gettype should work for different nodes') diff --git a/libs/remix-analyzer/test/analysis/staticAnalysisIntegration-test-0.5.0.ts b/libs/remix-analyzer/test/analysis/staticAnalysisIntegration-test-0.5.0.ts index 03cc61d5e2..18881e20ef 100644 --- a/libs/remix-analyzer/test/analysis/staticAnalysisIntegration-test-0.5.0.ts +++ b/libs/remix-analyzer/test/analysis/staticAnalysisIntegration-test-0.5.0.ts @@ -816,11 +816,11 @@ test('Integration test forLoopIteratesOverDynamicArray module', function (t: tes function runModuleOnFiles (Module: any, t: test.Test, cb: ((fname: string, report: AnalysisReportObj[]) => void)): void { const statRunner: StatRunner = new StatRunner() testFiles.forEach((fileName: string) => { - const reports = statRunner.runWithModuleList(compilationResults[fileName], [{ name: new Module().name, mod: new Module() }]) - const report: AnalysisReportObj[] = reports[0].report - if (report.some((x: AnalysisReportObj) => x['warning'].includes('INTERNAL ERROR'))) { - t.comment('Error while executing Module: ' + JSON.stringify(report)) - } - cb(fileName, report) + const reports = statRunner.runWithModuleList(compilationResults[fileName], [{ name: new Module().name, mod: new Module() }]) + const report: AnalysisReportObj[] = reports[0].report + if (report.some((x: AnalysisReportObj) => x['warning'].includes('INTERNAL ERROR'))) { + t.comment('Error while executing Module: ' + JSON.stringify(report)) + } + cb(fileName, report) }) } diff --git a/libs/remix-astwalker/README.md b/libs/remix-astwalker/README.md index 6b03957968..067c8d63c1 100644 --- a/libs/remix-astwalker/README.md +++ b/libs/remix-astwalker/README.md @@ -35,7 +35,7 @@ astWalker.on("node", node => { Please feel free to open an issue or a pull request. -In case you want to add some code, do have a look to our contribution guidelnes [here](https://github.com/ethereum/remix-project/blob/master/CONTRIBUTING.md). Reach us on [Gitter](https://gitter.im/ethereum/remix) in case of any queries. +In case you want to add some code, do have a look at our contribution guidelines [here](https://github.com/ethereum/remix-project/blob/master/CONTRIBUTING.md). Reach us on [Gitter](https://gitter.im/ethereum/remix) in case of any queries. ### License MIT © 2018-21 Remix Team diff --git a/libs/remix-astwalker/package.json b/libs/remix-astwalker/package.json index 11c7d507da..636700b360 100644 --- a/libs/remix-astwalker/package.json +++ b/libs/remix-astwalker/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-astwalker", - "version": "0.0.59", + "version": "0.0.63", "description": "Tool to walk through Solidity AST", "main": "src/index.js", "scripts": { @@ -37,7 +37,7 @@ "@ethereumjs/tx": "^4.1.1", "@ethereumjs/util": "^8.0.5", "@ethereumjs/vm": "^6.4.1", - "@remix-project/remix-lib": "^0.5.36", + "@remix-project/remix-lib": "^0.5.40", "@types/tape": "^4.2.33", "async": "^2.6.2", "ethers": "^5.4.2", @@ -53,6 +53,6 @@ "tap-spec": "^5.0.0" }, "typings": "src/index.d.ts", - "gitHead": "bd494e84f12d18787433f25b7dea264c7b2063f8", + "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220", "types": "./src/index.d.ts" } \ No newline at end of file diff --git a/libs/remix-astwalker/src/sourceMappings.ts b/libs/remix-astwalker/src/sourceMappings.ts index 869f495946..69b279d608 100644 --- a/libs/remix-astwalker/src/sourceMappings.ts +++ b/libs/remix-astwalker/src/sourceMappings.ts @@ -56,7 +56,7 @@ export function sourceLocationFromSrc (src: string): Location { /** * Routines for retrieving solc AST object(s) using some criteria, usually - * includng "src' information. + * including "src' information. */ // eslint-disable-next-line no-redeclare export class SourceMappings { diff --git a/libs/remix-astwalker/src/types.ts b/libs/remix-astwalker/src/types.ts index 784323d221..469d32c914 100644 --- a/libs/remix-astwalker/src/types.ts +++ b/libs/remix-astwalker/src/types.ts @@ -6,7 +6,7 @@ export interface Location { file: number; // Would it be clearer to call this a file index? } -// This is intended to be compatibile with VScode's Position. +// This is intended to be compatible with VScode's Position. // However it is pretty common with other things too. // Note: File index is missing here export interface LineColPosition { @@ -14,7 +14,7 @@ export interface LineColPosition { readonly character: number; } -// This is intended to be compatibile with vscode's Range +// This is intended to be compatible with vscode's Range // However it is pretty common with other things too. // Note: File index is missing here export interface LineColRange { diff --git a/libs/remix-core-plugin/src/lib/compiler-artefacts.ts b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts index b1f9ac9634..c37e3a7dab 100644 --- a/libs/remix-core-plugin/src/lib/compiler-artefacts.ts +++ b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts @@ -95,7 +95,7 @@ export class CompilerArtefacts extends Plugin { * filter compilation output for contracts compiled during a session of Remix IDE * @returns compilatin output */ - filterAllContractDatas (filter) { + filterAllContractDatas (filter) { const contractsData = {} Object.keys(this.compilersArtefactsPerFile).map((targetFile) => { const artefact = this.compilersArtefactsPerFile[targetFile] diff --git a/libs/remix-core-plugin/src/lib/compiler-content-imports.ts b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts index b64308ff34..50b9b08bb2 100644 --- a/libs/remix-core-plugin/src/lib/compiler-content-imports.ts +++ b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts @@ -167,8 +167,8 @@ export class CompilerImports extends Plugin { 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 === 'remix_tests.sol' || url === 'remix_accounts.sol')) { - await this.call('solidityUnitTesting', 'createTestLibs') - exist = await provider.exists(url) + await this.call('solidityUnitTesting', 'createTestLibs') + exist = await provider.exists(url) } if (!exist && url.startsWith('browser/')) throw new Error(`not found ${url}`) if (!exist && url.startsWith('localhost/')) throw new Error(`not found ${url}`) diff --git a/libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts b/libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts index 3030321f93..d004888a58 100644 --- a/libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts +++ b/libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts @@ -4,7 +4,7 @@ import { util } from '@remix-project/remix-lib' import { toChecksumAddress } from '@ethereumjs/util' import { fetchContractFromEtherscan } from './helpers/fetch-etherscan' import { fetchContractFromSourcify } from './helpers/fetch-sourcify' -import { UUPSDeployedByteCode, UUPSCompilerVersion, UUPSOptimize, UUPSRuns, UUPSEvmVersion, UUPSLanguage } from './constants/uups' +import { UUPSDeployedByteCode, UUPSCompilerVersion, UUPSOptimize, UUPSRuns, UUPSEvmVersion, UUPSLanguage, UUPSDeployedByteCodeV5, UUPSCompilerVersionV5 } from './constants/uups' const profile = { name: 'fetchAndCompile', @@ -84,6 +84,34 @@ export class FetchAndCompile extends Plugin { return compData } + if (codeAtAddress === '0x' + UUPSDeployedByteCodeV5) { // proxy + const settings = { + version: UUPSCompilerVersionV5, + language: UUPSLanguage, + evmVersion: UUPSEvmVersion, + optimize: UUPSOptimize, + runs: UUPSRuns + } + const proxyUrl = 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.0/contracts/proxy/ERC1967/ERC1967Proxy.sol' + const compilationTargets = { + 'proxy.sol': { content: `import "${proxyUrl}";` } + } + const compData = await compile( + compilationTargets, + settings, + async (url, cb) => { + // we first try to resolve the content from the compilation target using a more appropiate path + const path = `${targetPath}/${url}` + if (compilationTargets[path] && compilationTargets[path].content) { + return cb(null, compilationTargets[path].content) + } else { + 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 + } + // sometimes when doing an internal call, the only available artifact is the Solidity interface. // resolving addresses of internal call would allow to step over the source code, even if the declaration was made using an Interface. diff --git a/libs/remix-core-plugin/src/lib/compiler-metadata.ts b/libs/remix-core-plugin/src/lib/compiler-metadata.ts index abf811551c..b45daeb5f0 100644 --- a/libs/remix-core-plugin/src/lib/compiler-metadata.ts +++ b/libs/remix-core-plugin/src/lib/compiler-metadata.ts @@ -88,10 +88,10 @@ export class CompilerMetadata extends Plugin { const buildData = {id, _format: format, solcVersion, solcLongVersion, input, output} await this.call('fileManager', 'writeFile', buildFilename, JSON.stringify(buildData, null, '\t')) } else if (this.buildInfoNames[filePath] && this.buildInfoNames[filePath] !== buildFilename) { - await this.call('fileManager', 'remove', this.buildInfoNames[filePath]) - this.buildInfoNames[filePath] = buildFilename - const buildData = {id, _format: format, solcVersion, solcLongVersion, input, output} - await this.call('fileManager', 'writeFile', buildFilename, JSON.stringify(buildData, null, '\t')) + await this.call('fileManager', 'remove', this.buildInfoNames[filePath]) + this.buildInfoNames[filePath] = buildFilename + const buildData = {id, _format: format, solcVersion, solcLongVersion, input, output} + await this.call('fileManager', 'writeFile', buildFilename, JSON.stringify(buildData, null, '\t')) } } diff --git a/libs/remix-core-plugin/src/lib/constants/uups.ts b/libs/remix-core-plugin/src/lib/constants/uups.ts index 9a3dc92757..3a07dfdc8d 100644 --- a/libs/remix-core-plugin/src/lib/constants/uups.ts +++ b/libs/remix-core-plugin/src/lib/constants/uups.ts @@ -2,114 +2,169 @@ export const UUPS = 'UUPSUpgradeable' // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.0/contracts/proxy/ERC1967/ERC1967Proxy.sol // solidity 0.8.7 export const UUPSBytecode = '608060405260405162000c6638038062000c6683398181016040528101906200002991906200041e565b6200003d828260006200004560201b60201c565b5050620007e2565b62000056836200008860201b60201c565b600082511180620000645750805b156200008357620000818383620000df60201b620000371760201c565b505b505050565b62000099816200011560201b60201c565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b60606200010d838360405180606001604052806027815260200162000c3f60279139620001eb60201b60201c565b905092915050565b6200012b816200027d60201b620000641760201c565b6200016d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620001649062000587565b60405180910390fd5b80620001a77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b620002a060201b620000871760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516200021791906200054a565b600060405180830381855af49150503d806000811462000254576040519150601f19603f3d011682016040523d82523d6000602084013e62000259565b606091505b50915091506200027286838387620002aa60201b60201c565b925050509392505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b606083156200031b576000835114156200031257620002cf856200027d60201b60201c565b62000311576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200030890620005a9565b60405180910390fd5b5b8290506200032e565b6200032d83836200033660201b60201c565b5b949350505050565b6000825111156200034a5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000380919062000563565b60405180910390fd5b6000620003a06200039a84620005f4565b620005cb565b905082815260208101848484011115620003bf57620003be62000730565b5b620003cc84828562000690565b509392505050565b600081519050620003e581620007c8565b92915050565b600082601f8301126200040357620004026200072b565b5b81516200041584826020860162000389565b91505092915050565b600080604083850312156200043857620004376200073a565b5b60006200044885828601620003d4565b925050602083015167ffffffffffffffff8111156200046c576200046b62000735565b5b6200047a85828601620003eb565b9150509250929050565b600062000491826200062a565b6200049d818562000640565b9350620004af81856020860162000690565b80840191505092915050565b6000620004c88262000635565b620004d481856200064b565b9350620004e681856020860162000690565b620004f1816200073f565b840191505092915050565b60006200050b602d836200064b565b9150620005188262000750565b604082019050919050565b600062000532601d836200064b565b91506200053f826200079f565b602082019050919050565b600062000558828462000484565b915081905092915050565b600060208201905081810360008301526200057f8184620004bb565b905092915050565b60006020820190508181036000830152620005a281620004fc565b9050919050565b60006020820190508181036000830152620005c48162000523565b9050919050565b6000620005d7620005ea565b9050620005e58282620006c6565b919050565b6000604051905090565b600067ffffffffffffffff821115620006125762000611620006fc565b5b6200061d826200073f565b9050602081019050919050565b600081519050919050565b600081519050919050565b600081905092915050565b600082825260208201905092915050565b6000620006698262000670565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60005b83811015620006b057808201518184015260208101905062000693565b83811115620006c0576000848401525b50505050565b620006d1826200073f565b810181811067ffffffffffffffff82111715620006f357620006f2620006fc565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b620007d3816200065c565b8114620007df57600080fd5b50565b61044d80620007f26000396000f3fe6080604052366100135761001161001d565b005b61001b61001d565b005b610025610091565b610035610030610093565b6100a2565b565b606061005c83836040518060600160405280602781526020016103f1602791396100c8565b905092915050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b565b600061009d61014e565b905090565b3660008037600080366000845af43d6000803e80600081146100c3573d6000f35b3d6000fd5b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516100f291906102f8565b600060405180830381855af49150503d806000811461012d576040519150601f19603f3d011682016040523d82523d6000602084013e610132565b606091505b5091509150610143868383876101a5565b925050509392505050565b600061017c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b610087565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6060831561020857600083511415610200576101c085610064565b6101ff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f690610331565b60405180910390fd5b5b829050610213565b610212838361021b565b5b949350505050565b60008251111561022e5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610262919061030f565b60405180910390fd5b600061027682610351565b6102808185610367565b9350610290818560208601610383565b80840191505092915050565b60006102a78261035c565b6102b18185610372565b93506102c1818560208601610383565b6102ca816103b6565b840191505092915050565b60006102e2601d83610372565b91506102ed826103c7565b602082019050919050565b6000610304828461026b565b915081905092915050565b60006020820190508181036000830152610329818461029c565b905092915050565b6000602082019050818103600083015261034a816102d5565b9050919050565b600081519050919050565b600081519050919050565b600081905092915050565b600082825260208201905092915050565b60005b838110156103a1578082015181840152602081019050610386565b838111156103b0576000848401525b50505050565b6000601f19601f8301169050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060008201525056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122055b27d4c39ab82b8890fc1565c3858a1b7f1e0f5780871061f908d7503dcf94e64736f6c63430008070033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564' +export const UUPSBytecodeV5 = '60806040526040516106ae3803806106ae833981810160405281019061002591906104f2565b610035828261003c60201b60201c565b50506105ce565b61004b826100c060201b60201c565b8173ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a25f815111156100ad576100a7828261018f60201b60201c565b506100bc565b6100bb61021560201b60201c565b5b5050565b5f8173ffffffffffffffffffffffffffffffffffffffff163b0361011b57806040517f4c9c8ce3000000000000000000000000000000000000000000000000000000008152600401610112919061055b565b60405180910390fd5b8061014d7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5f1b61025160201b60201c565b5f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60605f808473ffffffffffffffffffffffffffffffffffffffff16846040516101b891906105b8565b5f60405180830381855af49150503d805f81146101f0576040519150601f19603f3d011682016040523d82523d5f602084013e6101f5565b606091505b509150915061020b85838361025a60201b60201c565b9250505092915050565b5f34111561024f576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f819050919050565b60608261027557610270826102ed60201b60201c565b6102e5565b5f825114801561029b57505f8473ffffffffffffffffffffffffffffffffffffffff163b145b156102dd57836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016102d4919061055b565b60405180910390fd5b8190506102e6565b5b9392505050565b5f815111156102ff5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61036b82610342565b9050919050565b61037b81610361565b8114610385575f80fd5b50565b5f8151905061039681610372565b92915050565b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6103ea826103a4565b810181811067ffffffffffffffff82111715610409576104086103b4565b5b80604052505050565b5f61041b610331565b905061042782826103e1565b919050565b5f67ffffffffffffffff821115610446576104456103b4565b5b61044f826103a4565b9050602081019050919050565b5f5b8381101561047957808201518184015260208101905061045e565b5f8484015250505050565b5f6104966104918461042c565b610412565b9050828152602081018484840111156104b2576104b16103a0565b5b6104bd84828561045c565b509392505050565b5f82601f8301126104d9576104d861039c565b5b81516104e9848260208601610484565b91505092915050565b5f80604083850312156105085761050761033a565b5b5f61051585828601610388565b925050602083015167ffffffffffffffff8111156105365761053561033e565b5b610542858286016104c5565b9150509250929050565b61055581610361565b82525050565b5f60208201905061056e5f83018461054c565b92915050565b5f81519050919050565b5f81905092915050565b5f61059282610574565b61059c818561057e565b93506105ac81856020860161045c565b80840191505092915050565b5f6105c38284610588565b915081905092915050565b60d4806105da5f395ff3fe6080604052600a600c565b005b60186014601a565b6026565b565b5f60216044565b905090565b365f80375f80365f845af43d5f803e805f81146040573d5ff35b3d5ffd5b5f606e7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5f1b6095565b5f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b5f81905091905056fea26469706673582212202e577dc05daa509bce6e6a86e29397d40b31118aea9fcd0aa88768ad25c610f964736f6c63430008150033' export const UUPSDeployedByteCode = '6080604052366100135761001161001d565b005b61001b61001d565b005b610025610091565b610035610030610093565b6100a2565b565b606061005c83836040518060600160405280602781526020016103f1602791396100c8565b905092915050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b565b600061009d61014e565b905090565b3660008037600080366000845af43d6000803e80600081146100c3573d6000f35b3d6000fd5b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516100f291906102f8565b600060405180830381855af49150503d806000811461012d576040519150601f19603f3d011682016040523d82523d6000602084013e610132565b606091505b5091509150610143868383876101a5565b925050509392505050565b600061017c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b610087565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6060831561020857600083511415610200576101c085610064565b6101ff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f690610331565b60405180910390fd5b5b829050610213565b610212838361021b565b5b949350505050565b60008251111561022e5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610262919061030f565b60405180910390fd5b600061027682610351565b6102808185610367565b9350610290818560208601610383565b80840191505092915050565b60006102a78261035c565b6102b18185610372565b93506102c1818560208601610383565b6102ca816103b6565b840191505092915050565b60006102e2601d83610372565b91506102ed826103c7565b602082019050919050565b6000610304828461026b565b915081905092915050565b60006020820190508181036000830152610329818461029c565b905092915050565b6000602082019050818103600083015261034a816102d5565b9050919050565b600081519050919050565b600081519050919050565b600081905092915050565b600082825260208201905092915050565b60005b838110156103a1578082015181840152602081019050610386565b838111156103b0576000848401525b50505050565b6000601f19601f8301169050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060008201525056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122055b27d4c39ab82b8890fc1565c3858a1b7f1e0f5780871061f908d7503dcf94e64736f6c63430008070033' +export const UUPSDeployedByteCodeV5 = '6080604052600a600c565b005b60186014601a565b6026565b565b5f60216044565b905090565b365f80375f80365f845af43d5f803e805f81146040573d5ff35b3d5ffd5b5f606e7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5f1b6095565b5f015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b5f81905091905056fea26469706673582212202e577dc05daa509bce6e6a86e29397d40b31118aea9fcd0aa88768ad25c610f964736f6c63430008150033' export const UUPSCompilerVersion = 'soljson-v0.8.7+commit.e28d00a7.js' +export const UUPSCompilerVersionV5 = 'soljson-v0.8.21+commit.d9974bed.js' export const UUPSLanguage = 'Solidity' export const UUPSOptimize = false export const UUPSRuns = 0 export const UUPSEvmVersion = null export const UUPSABI = [ { - "inputs": [ - { - "internalType": "address", - "name": "_logic", - "type": "address" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "stateMutability": "payable", - "type": "constructor" + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "previousAdmin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminChanged", - "type": "event" + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "beacon", - "type": "address" - } - ], - "name": "BeaconUpgraded", - "type": "event" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" }, { - "stateMutability": "payable", - "type": "fallback" + "stateMutability": "payable", + "type": "fallback" }, { - "stateMutability": "payable", - "type": "receive" + "stateMutability": "payable", + "type": "receive" } ] export const UUPSfunAbi = { name: "", inputs: [ - { - "internalType": "address", - "name": "_logic", - "type": "address" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } ], type: "constructor", outputs: [], stateMutability: "payable" } +export const UUPSfunAbiV5 = { + inputs: [ + { + internalType: 'address', + name: 'implementation', + type: 'address', + }, + { + internalType: 'bytes', + name: '_data', + type: 'bytes', + }, + ], + stateMutability: 'payable', + type: 'constructor', +} + export const UUPSupgradeAbi = { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - } - ], - "name": "upgradeTo", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" +} + + +export const UUPSupgradeToAndCallAbi = { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" } + +export const GETUUPSProxyVersionAbi = { + "inputs": [], + "name": "UPGRADE_INTERFACE_VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" +} + export const EnableProxyURLParam = 'deployProxy' export const EnableUpgradeURLParam = 'upgradeProxy' \ No newline at end of file diff --git a/libs/remix-core-plugin/src/lib/helpers/fetch-etherscan.ts b/libs/remix-core-plugin/src/lib/helpers/fetch-etherscan.ts index 1592663c38..5cc8460d72 100644 --- a/libs/remix-core-plugin/src/lib/helpers/fetch-etherscan.ts +++ b/libs/remix-core-plugin/src/lib/helpers/fetch-etherscan.ts @@ -1,10 +1,8 @@ -export const fetchContractFromEtherscan = async (plugin, network, contractAddress, targetPath, shouldSetFile = true, key?) => { +export const fetchContractFromEtherscan = async (plugin, network, contractAddress, targetPath, shouldSetFile = true, etherscanKey?) => { let data const compilationTargets = {} - let etherscanKey - - if (!key) etherscanKey = await plugin.call('config', 'getAppParameter', 'etherscan-access-token') - else etherscanKey = key + if (!etherscanKey) etherscanKey = await plugin.call('config', 'getAppParameter', 'etherscan-access-token') + if (!etherscanKey) etherscanKey = '2HKUX5ZVASZIKWJM8MIQVCRUVZ6JAWT531' if (etherscanKey) { const endpoint = network.id == 1 ? 'api.etherscan.io' : 'api-' + network.name + '.etherscan.io' @@ -63,4 +61,4 @@ export const fetchContractFromEtherscan = async (plugin, network, contractAddres settings, compilationTargets } -} \ No newline at end of file +} diff --git a/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts b/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts index 47db52425f..661ead7a6f 100644 --- a/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts +++ b/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts @@ -1,7 +1,9 @@ import { Plugin } from '@remixproject/engine' import { ContractAST, ContractSources, DeployOptions } from '../types/contract' -import { EnableProxyURLParam, EnableUpgradeURLParam, UUPS, UUPSABI, UUPSBytecode, UUPSfunAbi, UUPSupgradeAbi } from './constants/uups' - +import { EnableProxyURLParam, EnableUpgradeURLParam, GETUUPSProxyVersionAbi, UUPS, UUPSABI, UUPSBytecode, UUPSBytecodeV5, UUPSfunAbi, UUPSfunAbiV5, UUPSupgradeAbi, UUPSupgradeToAndCallAbi } from './constants/uups' +import * as remixLib from '@remix-project/remix-lib' +import * as semver from 'semver' +const txFormat = remixLib.execution.txFormat const proxyProfile = { name: 'openzeppelin-proxy', displayName: 'openzeppelin-proxy', @@ -30,18 +32,18 @@ export class OpenZeppelinProxy extends Plugin { return false } - async getProxyOptions (data: ContractSources, file: string): Promise<{ [name: string]: DeployOptions }> { + async getProxyOptions(data: ContractSources, file: string): Promise<{ [name: string]: DeployOptions }> { const contracts = data.contracts[file] const ast = data.sources[file].ast if (this.kind === 'UUPS') { - const options = await (this.getUUPSContractOptions(contracts, ast, file)) + const options = await this.getUUPSContractOptions(contracts, ast, file) return options } } - async getUUPSContractOptions (contracts, ast, file) { + async getUUPSContractOptions(contracts, ast, file) { const options = {} await Promise.all(Object.keys(contracts).map(async (name) => { @@ -54,7 +56,7 @@ export class OpenZeppelinProxy extends Plugin { const initializeInput = abi.find(node => node.name === 'initialize') const isDeployWithProxyEnabled: boolean = await this.call('config', 'getAppParameter', EnableProxyURLParam) || false const isDeployWithUpgradeEnabled: boolean = await this.call('config', 'getAppParameter', EnableUpgradeURLParam) || false - + options[name] = { options: [{ title: 'Deploy with Proxy', active: isDeployWithProxyEnabled }, { title: 'Upgrade with Proxy', active: isDeployWithUpgradeEnabled }], initializeOptions: { @@ -69,7 +71,7 @@ export class OpenZeppelinProxy extends Plugin { return options } - async executeUUPSProxy(implAddress: string, args: string | string [] = '', initializeABI, implementationContractObject): Promise { + async executeUUPSProxy(implAddress: string, args: string | string[] = '', initializeABI, implementationContractObject): Promise { // deploy the proxy, or use an existing one if (!initializeABI) throw new Error('Cannot deploy proxy: Missing initialize ABI') args = args === '' ? [] : args @@ -78,27 +80,38 @@ export class OpenZeppelinProxy extends Plugin { if (this.kind === 'UUPS') this.deployUUPSProxy(implAddress, _data, implementationContractObject) } - async executeUUPSContractUpgrade (proxyAddress: string, newImplAddress: string, newImplementationContractObject): Promise { + async executeUUPSContractUpgrade(proxyAddress: string, newImplAddress: string, newImplementationContractObject): Promise { if (!newImplAddress) throw new Error('Cannot upgrade: Missing implementation address') if (!proxyAddress) throw new Error('Cannot upgrade: Missing proxy address') if (this.kind === 'UUPS') this.upgradeUUPSProxy(proxyAddress, newImplAddress, newImplementationContractObject) } - async deployUUPSProxy (implAddress: string, _data: string, implementationContractObject): Promise { + async deployUUPSProxy(implAddress: string, _data: string, implementationContractObject): Promise { + const args = [implAddress, _data] const constructorData = await this.blockchain.getEncodedParams(args, UUPSfunAbi) const proxyName = 'ERC1967Proxy' const data = { contractABI: UUPSABI, - contractByteCode: UUPSBytecode, + contractByteCode: UUPSBytecodeV5, contractName: proxyName, - funAbi: UUPSfunAbi, + funAbi: UUPSfunAbiV5, funArgs: args, linkReferences: {}, - dataHex: UUPSBytecode + constructorData.replace('0x', '') + dataHex: UUPSBytecodeV5 + constructorData.replace('0x', ''), + } + // check if implementation contract has a function called UPGRADE_INTERFACE_VERSION + // if it hasn't then we use the old bytecode pre 5.0.0 + const hasUpgradeVersionCall = implementationContractObject.abi.find((abi) => abi.name === 'UPGRADE_INTERFACE_VERSION') + if (!hasUpgradeVersionCall) { + data.contractByteCode = UUPSBytecode + data.dataHex = UUPSBytecode + constructorData.replace('0x', '') + data.funAbi = UUPSfunAbi + this.call('terminal', 'logHtml', `Deploying ERC1967 < 5.0.0 as proxy...`) + }else{ + this.call('terminal', 'logHtml', `Deploying ERC1967 >= 5.0.0 as proxy...`) } - // re-use implementation contract's ABI for UI display in udapp and change name to proxy name. implementationContractObject.contractName = implementationContractObject.name implementationContractObject.implementationAddress = implAddress @@ -106,21 +119,68 @@ export class OpenZeppelinProxy extends Plugin { this.blockchain.deployProxy(data, implementationContractObject) } - async upgradeUUPSProxy (proxyAddress: string, newImplAddress: string, newImplementationContractObject): Promise { - const fnData = await this.blockchain.getEncodedFunctionHex([newImplAddress], UUPSupgradeAbi) + async upgradeUUPSProxy(proxyAddress: string, newImplAddress: string, newImplementationContractObject): Promise { const proxyName = 'ERC1967Proxy' - const data = { - contractABI: UUPSABI, - contractName: proxyName, - funAbi: UUPSupgradeAbi, - funArgs: [newImplAddress], - linkReferences: {}, - dataHex: fnData.replace('0x', '') + const dataHex = await this.blockchain.getEncodedFunctionHex([], GETUUPSProxyVersionAbi) + const args = { + to: proxyAddress, + data: { + contractABI: undefined, + dataHex: dataHex, + funAbi: GETUUPSProxyVersionAbi, + contractName: proxyName, + funArgs: [], + }, + useCall: true, } // re-use implementation contract's ABI for UI display in udapp and change name to proxy name. newImplementationContractObject.contractName = newImplementationContractObject.name newImplementationContractObject.implementationAddress = newImplAddress newImplementationContractObject.name = proxyName - this.blockchain.upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject) + + await this.blockchain.runTx( + args, + () => {}, + () => {}, + () => {}, + async (error, txResult, _address, returnValue) => { + let version = '4.8.3' + if (error) { + console.log(`error: ${error.message ? error.message : error}`) + } else { + const response = txFormat.decodeResponse(returnValue, GETUUPSProxyVersionAbi) + version = response[0].split('string: ')[1] + // check if version is >= 5.0.0 + } + + if (semver.gte(version, '5.0.0')) { + const fnData = await this.blockchain.getEncodedFunctionHex([newImplAddress, '0x'], UUPSupgradeToAndCallAbi) + + const data = { + contractABI: UUPSABI, + contractName: proxyName, + funAbi: UUPSupgradeToAndCallAbi, + funArgs: [newImplAddress, '0x'], + linkReferences: {}, + dataHex: fnData.replace('0x', ''), + } + this.call('terminal', 'logHtml', `Using ERC1967 >= 5.0.0 for the proxy upgrade...`) + this.blockchain.upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject) + } else { + const fnData = await this.blockchain.getEncodedFunctionHex([newImplAddress], UUPSupgradeAbi) + const proxyName = 'ERC1967Proxy' + const data = { + contractABI: UUPSABI, + contractName: proxyName, + funAbi: UUPSupgradeAbi, + funArgs: [newImplAddress], + linkReferences: {}, + dataHex: fnData.replace('0x', ''), + } + this.call('terminal', 'logHtml', `Using ERC1967 < 5.0.0 for the proxy upgrade...`) + this.blockchain.upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject) + } + } + ) } -} \ No newline at end of file +} diff --git a/libs/remix-core-plugin/src/types/contract.ts b/libs/remix-core-plugin/src/types/contract.ts index ba93c138f0..df518ed034 100644 --- a/libs/remix-core-plugin/src/types/contract.ts +++ b/libs/remix-core-plugin/src/types/contract.ts @@ -191,7 +191,7 @@ export interface ContractSources { } } - export interface NetworkDeploymentFile { +export interface NetworkDeploymentFile { id: string, network: string, deployments: { @@ -204,7 +204,7 @@ export interface ContractSources { }[] } - export interface SolcBuildFile { +export interface SolcBuildFile { solcInput: SolcInput, solcOutput: SolcOutput } diff --git a/libs/remix-debug/README.md b/libs/remix-debug/README.md index e512499d36..a59e9690ac 100644 --- a/libs/remix-debug/README.md +++ b/libs/remix-debug/README.md @@ -5,7 +5,7 @@ [![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/ethereum/remix-project/tree/master/libs/remix-debug) [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/ethereum/remix-project/issues) -`@remix-project/remix-debug` is a tool to debug Ethereum transactions on different Remix environments (VM, testnet etc.). It works underneath Remix IDE "DEBUGGER" plugin which is used to analyse step-to-step executioon of a transaction to debug it. +`@remix-project/remix-debug` is a tool to debug Ethereum transactions on different Remix environments (VM, testnet etc.). It works underneath Remix IDE "DEBUGGER" plugin which is used to analyse step-to-step execution of a transaction to debug it. ### Installation `@remix-project/remix-debug` is an NPM package and can be installed using NPM as: @@ -144,7 +144,7 @@ Some of the class details are as: Please feel free to open an issue or a pull request. -In case you want to add some code, do have a look to our contribution guidelnes [here](https://github.com/ethereum/remix-project/blob/master/CONTRIBUTING.md). Reach us on [Gitter](https://gitter.im/ethereum/remix) in case of any queries. +In case you want to add some code, do have a look at our contribution guidelines [here](https://github.com/ethereum/remix-project/blob/master/CONTRIBUTING.md). Reach us on [Gitter](https://gitter.im/ethereum/remix) in case of any queries. ### License MIT © 2018-21 Remix Team diff --git a/libs/remix-debug/package.json b/libs/remix-debug/package.json index a00c0dc997..32799caf49 100644 --- a/libs/remix-debug/package.json +++ b/libs/remix-debug/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-debug", - "version": "0.5.29", + "version": "0.5.33", "description": "Tool to debug Ethereum transactions", "contributors": [ { @@ -26,10 +26,10 @@ "@ethereumjs/tx": "^4.1.1", "@ethereumjs/util": "^8.0.5", "@ethereumjs/vm": "^6.4.1", - "@remix-project/remix-astwalker": "^0.0.59", - "@remix-project/remix-lib": "^0.5.36", - "@remix-project/remix-simulator": "^0.2.29", - "@remix-project/remix-solidity": "^0.5.15", + "@remix-project/remix-astwalker": "^0.0.63", + "@remix-project/remix-lib": "^0.5.40", + "@remix-project/remix-simulator": "^0.2.33", + "@remix-project/remix-solidity": "^0.5.19", "ansi-gray": "^0.1.1", "async": "^2.6.2", "color-support": "^1.1.3", @@ -69,6 +69,6 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme", "typings": "src/index.d.ts", - "gitHead": "bd494e84f12d18787433f25b7dea264c7b2063f8", + "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220", "types": "./src/index.d.ts" } \ No newline at end of file diff --git a/libs/remix-debug/src/init.ts b/libs/remix-debug/src/init.ts index 700c9f5822..fab25c5039 100644 --- a/libs/remix-debug/src/init.ts +++ b/libs/remix-debug/src/init.ts @@ -19,7 +19,7 @@ export function setProvider (web3, url) { export function web3DebugNode (network) { const web3DebugNodes = { - Main: 'https://rpc.archivenode.io/e50zmkroshle2e2e50zm0044i7ao04ym', + Main: 'https://eth.getblock.io/68069907-1d3c-466e-a533-a943afd935c6/mainnet', Rinkeby: 'https://remix-rinkeby.ethdevops.io', Ropsten: 'https://remix-ropsten.ethdevops.io', Goerli: 'https://remix-goerli.ethdevops.io', diff --git a/libs/remix-debug/src/trace/traceCache.ts b/libs/remix-debug/src/trace/traceCache.ts index 7c6f115277..af578c2568 100644 --- a/libs/remix-debug/src/trace/traceCache.ts +++ b/libs/remix-debug/src/trace/traceCache.ts @@ -102,11 +102,13 @@ export class TraceCache { } pushContractCreationFromMemory (index, token, trace, lastMemoryChange) { + const toHexString = arr => Array.from(arr, i => (i as any).toString(16).padStart(2, "0")).join("") const memory = trace[lastMemoryChange].memory const stack = trace[index].stack const offset = 2 * parseInt(toHexPaddedString(stack[stack.length - 2]), 16) const size = 2 * parseInt(toHexPaddedString(stack[stack.length - 3]), 16) - this.contractCreation[token] = '0x' + memory.join('').substr(offset, size) + const memoryHex = toHexString(memory) + this.contractCreation[token] = '0x' + memoryHex.substr(offset, size) } pushContractCreation (token, code) { diff --git a/libs/remix-debug/test.ts b/libs/remix-debug/test.ts index f0c43e4398..7ccb8bcc0f 100644 --- a/libs/remix-debug/test.ts +++ b/libs/remix-debug/test.ts @@ -10,8 +10,7 @@ const shortFilename = 'simple_storage.sol' const inputJson = { language: 'Solidity', - sources: { - }, + sources: {}, settings: { optimizer: { enabled: true, @@ -19,14 +18,16 @@ const inputJson = { }, outputSelection: { '*': { - '': [ 'ast' ], - '*': [ 'abi', 'metadata', 'devdoc', 'userdoc', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates' ] + '': ['ast'], + '*': ['abi', 'metadata', 'devdoc', 'userdoc', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates'] } } } } -inputJson.sources[shortFilename] = {content: fs.readFileSync(filename).toString()} +inputJson.sources[shortFilename] = { + content: fs.readFileSync(filename).toString() +} console.dir(inputJson) @@ -36,7 +37,7 @@ const compilationData = JSON.parse(solc.compileStandardWrapper(JSON.stringify(in console.dir(Object.keys(compilationData)) const compilation = {} compilation['data'] = compilationData -compilation['source'] = { sources: inputJson.sources } +compilation['source'] = {sources: inputJson.sources} console.dir(compilation) console.dir(compilation['data'].errors) @@ -67,7 +68,7 @@ cmdLine.startDebug(tx, shortFilename) cmdLine.events.on('source', () => { cmdLine.getSource().forEach(console.dir) }) - // }) +// }) // }) const repl = require('repl') @@ -106,4 +107,3 @@ repl.start({ }) module.exports = cmdLine - diff --git a/libs/remix-debug/test/decoder/localsTests/helper.ts b/libs/remix-debug/test/decoder/localsTests/helper.ts index c041f4364a..d966c16f5a 100644 --- a/libs/remix-debug/test/decoder/localsTests/helper.ts +++ b/libs/remix-debug/test/decoder/localsTests/helper.ts @@ -31,15 +31,15 @@ export function decodeLocals (st, index, traceManager, callTree, verifier) { callback(error) } }], - index, - function (error, result) { - if (error) { - return st.fail(error) - } - solidityLocals(index, callTree, result[0].value, result[1].value, {}, result[2].value, { start: 5000 }, null).then((locals) => { - verifier(locals) - }) + index, + function (error, result) { + if (error) { + return st.fail(error) + } + solidityLocals(index, callTree, result[0].value, result[1].value, {}, result[2].value, { start: 5000 }, null).then((locals) => { + verifier(locals) }) + }) } catch (e) { st.fail(e.message) } diff --git a/libs/remix-debug/test/decoder/stateTests/mapping.ts b/libs/remix-debug/test/decoder/stateTests/mapping.ts index b633be9c8f..52b457e8ce 100644 --- a/libs/remix-debug/test/decoder/stateTests/mapping.ts +++ b/libs/remix-debug/test/decoder/stateTests/mapping.ts @@ -46,63 +46,63 @@ module.exports = async function testMappingStorage (st, cb) { function testMapping (st, privateKey, contractAddress, output, compilationResults, web3, cb) { (vmCall as any).sendTx(web3, {nonce: 1, privateKey: privateKey}, contractAddress, 0, '2fd0a83a00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001074686973206973206120737472696e6700000000000000000000000000000000', - function (error, hash) { + function (error, hash) { + if (error) { + console.log(error) + st.end(error) + } else { + web3.eth.getTransaction(hash, (error, tx) => { if (error) { console.log(error) st.end(error) - } else { - web3.eth.getTransaction(hash, (error, tx) => { - if (error) { - console.log(error) - st.end(error) - } else { - const traceManager = new TraceManager({ web3 }) - const codeManager = new CodeManager(traceManager) - codeManager.clear() - console.log(compilationResults) - const solidityProxy = new SolidityProxy({ - getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), - getCode: codeManager.getCode.bind(codeManager), - compilationResult: () => compilationResults - }) - const debuggerEvent = new EventManager() - const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }) - callTree.event.register('callTreeBuildFailed', (error) => { - st.fail(error) - }) - callTree.event.register('callTreeNotReady', (reason) => { - st.fail(reason) - }) - callTree.event.register('callTreeReady', (scopes, scopeStarts) => { - const storageViewer = new StorageViewer({ - stepIndex: 268, - tx: tx, - address: contractAddress - }, new StorageResolver({web3}), traceManager) - const stateVars = stateDecoder.extractStateVariables('SimpleMappingState', output.sources) - stateDecoder.decodeState(stateVars, storageViewer).then((result) => { - st.equal(result['_num'].value, '1') - st.equal(result['_num'].type, 'uint256') - st.equal(result['_iBreakSolidityState'].type, 'mapping(string => uint256)') - st.equal(result['_iBreakSolidityState'].value['74686973206973206120737472696e67'].value, '1') - st.equal(result['_iBreakSolidityState'].value['74686973206973206120737472696e67'].type, 'uint256') - st.equal(result['_iBreakSolidityStateInt'].type, 'mapping(uint256 => uint256)') - st.equal(result['_iBreakSolidityStateInt'].value['0000000000000000000000000000000000000000000000000000000000000001'].value, '1') - st.equal(result['_iBreakSolidityStateInt'].value['0000000000000000000000000000000000000000000000000000000000000001'].type, 'uint256') - cb() - }, (reason) => { - console.log('fail') - st.end(reason) - }) - }) + } else { + const traceManager = new TraceManager({ web3 }) + const codeManager = new CodeManager(traceManager) + codeManager.clear() + console.log(compilationResults) + const solidityProxy = new SolidityProxy({ + getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), + getCode: codeManager.getCode.bind(codeManager), + compilationResult: () => compilationResults + }) + const debuggerEvent = new EventManager() + const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }) + callTree.event.register('callTreeBuildFailed', (error) => { + st.fail(error) + }) + callTree.event.register('callTreeNotReady', (reason) => { + st.fail(reason) + }) + callTree.event.register('callTreeReady', (scopes, scopeStarts) => { + const storageViewer = new StorageViewer({ + stepIndex: 268, + tx: tx, + address: contractAddress + }, new StorageResolver({web3}), traceManager) + const stateVars = stateDecoder.extractStateVariables('SimpleMappingState', output.sources) + stateDecoder.decodeState(stateVars, storageViewer).then((result) => { + st.equal(result['_num'].value, '1') + st.equal(result['_num'].type, 'uint256') + st.equal(result['_iBreakSolidityState'].type, 'mapping(string => uint256)') + st.equal(result['_iBreakSolidityState'].value['74686973206973206120737472696e67'].value, '1') + st.equal(result['_iBreakSolidityState'].value['74686973206973206120737472696e67'].type, 'uint256') + st.equal(result['_iBreakSolidityStateInt'].type, 'mapping(uint256 => uint256)') + st.equal(result['_iBreakSolidityStateInt'].value['0000000000000000000000000000000000000000000000000000000000000001'].value, '1') + st.equal(result['_iBreakSolidityStateInt'].value['0000000000000000000000000000000000000000000000000000000000000001'].type, 'uint256') + cb() + }, (reason) => { + console.log('fail') + st.end(reason) + }) + }) - traceManager.resolveTrace(tx).then(() => { - debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) - }).catch((error) => { - st.fail(error) - }) - } + traceManager.resolveTrace(tx).then(() => { + debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) + }).catch((error) => { + st.fail(error) }) } }) + } + }) } diff --git a/libs/remix-debug/test/resources/ast.ts b/libs/remix-debug/test/resources/ast.ts index 03fad53a77..f4ca65f47e 100644 --- a/libs/remix-debug/test/resources/ast.ts +++ b/libs/remix-debug/test/resources/ast.ts @@ -3,64 +3,64 @@ const node = {} node['ast'] = {"legacyAST":{"children":[{"attributes":{"fullyImplemented":true,"isLibrary":false,"linearizedBaseContracts":[5640396],"name":"test"},"children":[{"attributes":{"name":"x","type":"int256"},"children":[{"attributes":{"name":"int"},"id":5657860,"name":"ElementaryTypeName","src":"21:3:11"}],"id":5658100,"name":"VariableDeclaration","src":"21:5:11"},{"attributes":{"name":"y","type":"int256"},"children":[{"attributes":{"name":"int"},"id":5658180,"name":"ElementaryTypeName","src":"38:3:11"}],"id":5658268,"name":"VariableDeclaration","src":"38:5:11"},{"attributes":{"constant":false,"name":"set","public":true},"children":[{"children":[{"attributes":{"name":"_x","type":"int256"},"children":[{"attributes":{"name":"int"},"id":5658404,"name":"ElementaryTypeName","src":"68:3:11"}],"id":5658492,"name":"VariableDeclaration","src":"68:6:11"}],"id":5658572,"name":"ParameterList","src":"67:8:11"},{"children":[{"attributes":{"name":"_r","type":"int256"},"children":[{"attributes":{"name":"int"},"id":5658628,"name":"ElementaryTypeName","src":"85:3:11"}],"id":5658716,"name":"VariableDeclaration","src":"85:6:11"}],"id":5658796,"name":"ParameterList","src":"84:8:11"},{"children":[{"children":[{"attributes":{"operator":"=","type":"int256"},"children":[{"attributes":{"type":"int256","value":"x"},"id":5658900,"name":"Identifier","src":"108:1:11"},{"attributes":{"type":"int256","value":"_x"},"id":5658980,"name":"Identifier","src":"112:2:11"}],"id":5657492,"name":"Assignment","src":"108:6:11"}],"id":5659028,"name":"ExpressionStatement","src":"108:6:11"},{"children":[{"attributes":{"operator":"=","type":"int256"},"children":[{"attributes":{"type":"int256","value":"y"},"id":5659116,"name":"Identifier","src":"125:1:11"},{"attributes":{"string":null,"type":"int_const 10","value":"10"},"id":5659196,"name":"Literal","src":"129:2:11"}],"id":5659252,"name":"Assignment","src":"125:6:11"}],"id":5659316,"name":"ExpressionStatement","src":"125:6:11"},{"children":[{"attributes":{"operator":"=","type":"int256"},"children":[{"attributes":{"type":"int256","value":"_r"},"id":5659428,"name":"Identifier","src":"141:2:11"},{"attributes":{"type":"int256","value":"x"},"id":5639308,"name":"Identifier","src":"146:1:11"}],"id":5639356,"name":"Assignment","src":"141:6:11"}],"id":5639420,"name":"ExpressionStatement","src":"141:6:11"}],"id":5639516,"name":"Block","src":"97:57:11"}],"id":5639612,"name":"FunctionDefinition","src":"55:99:11"},{"attributes":{"constant":false,"name":"get","public":true},"children":[{"children":[],"id":5639764,"name":"ParameterList","src":"179:2:11"},{"children":[{"attributes":{"name":"x","type":"uint256"},"children":[{"attributes":{"name":"uint"},"id":5639820,"name":"ElementaryTypeName","src":"191:4:11"}],"id":5639908,"name":"VariableDeclaration","src":"191:6:11"},{"attributes":{"name":"y","type":"uint256"},"children":[{"attributes":{"name":"uint"},"id":5639988,"name":"ElementaryTypeName","src":"199:4:11"}],"id":5640076,"name":"VariableDeclaration","src":"199:6:11"}],"id":5640156,"name":"ParameterList","src":"190:16:11"},{"children":[],"id":5640212,"name":"Block","src":"212:17:11"}],"id":5640276,"name":"FunctionDefinition","src":"167:62:11"}],"id":5640396,"name":"ContractDefinition","src":"0:231:11"}],"name":"SourceUnit"}} node['ast'].ast = { - absolutePath: 'sample.sol', - exportedSymbols: { test: [ 33 ] }, - id: 34, - nodeType: 'SourceUnit', - nodes: + absolutePath: 'sample.sol', + exportedSymbols: { test: [ 33 ] }, + id: 34, + nodeType: 'SourceUnit', + nodes: [ { - abstract: false, - baseContracts: [], - contractDependencies: [], - contractKind: 'contract', - documentation: null, - fullyImplemented: true, - id: 33, - linearizedBaseContracts: [ 33 ], - name: 'test', - nodeType: 'ContractDefinition', - nodes: + abstract: false, + baseContracts: [], + contractDependencies: [], + contractKind: 'contract', + documentation: null, + fullyImplemented: true, + id: 33, + linearizedBaseContracts: [ 33 ], + name: 'test', + nodeType: 'ContractDefinition', + nodes: [ { constant: false, - id: 2, - name: 'x', - nodeType: 'VariableDeclaration', - overrides: null, - scope: 33, - src: '20:5:0', - stateVariable: true, - storageLocation: 'default', - typeDescriptions: { typeIdentifier: 't_int256', typeString: 'int256' }, - typeName: { - id: 1, - name: 'int', - nodeType: 'ElementaryTypeName', - src: '20:3:0', - typeDescriptions: [Object] - }, - value: null, - visibility: 'internal' }, + id: 2, + name: 'x', + nodeType: 'VariableDeclaration', + overrides: null, + scope: 33, + src: '20:5:0', + stateVariable: true, + storageLocation: 'default', + typeDescriptions: { typeIdentifier: 't_int256', typeString: 'int256' }, + typeName: { + id: 1, + name: 'int', + nodeType: 'ElementaryTypeName', + src: '20:3:0', + typeDescriptions: [Object] + }, + value: null, + visibility: 'internal' }, { constant: false, - id: 4, - name: 'y', - nodeType: 'VariableDeclaration', - overrides: null, - scope: 33, - src: '31:5:0', - stateVariable: true, - storageLocation: 'default', - typeDescriptions: { typeIdentifier: 't_int256', typeString: 'int256' }, - typeName: + id: 4, + name: 'y', + nodeType: 'VariableDeclaration', + overrides: null, + scope: 33, + src: '31:5:0', + stateVariable: true, + storageLocation: 'default', + typeDescriptions: { typeIdentifier: 't_int256', typeString: 'int256' }, + typeName: { id: 3, - name: 'int', - nodeType: 'ElementaryTypeName', - src: '31:3:0', - typeDescriptions: [Object] }, - value: null, - visibility: 'internal' }, + name: 'int', + nodeType: 'ElementaryTypeName', + src: '31:3:0', + typeDescriptions: [Object] }, + value: null, + visibility: 'internal' }, { body: { id: 23, - nodeType: 'Block', - src: '96:55:0', - statements: + nodeType: 'Block', + src: '96:55:0', + statements: [ { expression: { argumentTypes: null, id: 13, @@ -70,31 +70,31 @@ node['ast'].ast = { lValueRequested: false, leftHandSide: { argumentTypes: null, - id: 11, - name: 'x', - nodeType: 'Identifier', - overloadedDeclarations: [], - referencedDeclaration: 2, - src: '106:1:0', - typeDescriptions: { typeIdentifier: 't_int256', typeString: 'int256' } }, + id: 11, + name: 'x', + nodeType: 'Identifier', + overloadedDeclarations: [], + referencedDeclaration: 2, + src: '106:1:0', + typeDescriptions: { typeIdentifier: 't_int256', typeString: 'int256' } }, nodeType: 'Assignment', operator: '=', rightHandSide: { argumentTypes: null, - id: 12, - name: '_x', - nodeType: 'Identifier', - overloadedDeclarations: [], - referencedDeclaration: 6, - src: '110:2:0', - typeDescriptions: { typeIdentifier: 't_int256', typeString: 'int256' } }, + id: 12, + name: '_x', + nodeType: 'Identifier', + overloadedDeclarations: [], + referencedDeclaration: 6, + src: '110:2:0', + typeDescriptions: { typeIdentifier: 't_int256', typeString: 'int256' } }, src: '106:6:0', typeDescriptions: { typeIdentifier: 't_int256', typeString: 'int256' } }, - id: 14, - nodeType: 'ExpressionStatement', - src: '106:6:0' }, - { expression: + id: 14, + nodeType: 'ExpressionStatement', + src: '106:6:0' }, + { expression: { argumentTypes: null, id: 17, isConstant: false, @@ -107,10 +107,10 @@ node['ast'].ast = { rightHandSide: [Object], src: '122:6:0', typeDescriptions: [Object] }, - id: 18, - nodeType: 'ExpressionStatement', - src: '122:6:0' }, - { expression: + id: 18, + nodeType: 'ExpressionStatement', + src: '122:6:0' }, + { expression: { argumentTypes: null, id: 21, isConstant: false, @@ -123,61 +123,61 @@ node['ast'].ast = { rightHandSide: [Object], src: '138:6:0', typeDescriptions: [Object] }, - id: 22, - nodeType: 'ExpressionStatement', - src: '138:6:0' } ] - }, - documentation: null, - functionSelector: 'e5c19b2d', - id: 24, - implemented: true, - kind: 'function', - modifiers: [], - name: 'set', - nodeType: 'FunctionDefinition', - overrides: null, - parameters: { id: 7, - nodeType: 'ParameterList', - parameters: [Array], - src: '59:8:0' }, - returnParameters: { id: 10, - nodeType: 'ParameterList', - parameters: [Array], - src: '83:8:0' }, - scope: 33, - src: '47:104:0', - stateMutability: 'nonpayable', - virtual: false, - visibility: 'public' }, + id: 22, + nodeType: 'ExpressionStatement', + src: '138:6:0' } ] + }, + documentation: null, + functionSelector: 'e5c19b2d', + id: 24, + implemented: true, + kind: 'function', + modifiers: [], + name: 'set', + nodeType: 'FunctionDefinition', + overrides: null, + parameters: { id: 7, + nodeType: 'ParameterList', + parameters: [Array], + src: '59:8:0' }, + returnParameters: { id: 10, + nodeType: 'ParameterList', + parameters: [Array], + src: '83:8:0' }, + scope: 33, + src: '47:104:0', + stateMutability: 'nonpayable', + virtual: false, + visibility: 'public' }, { body: { id: 31, nodeType: 'Block', src: '214:17:0', statements: [] }, - documentation: null, - functionSelector: '6d4ce63c', - id: 32, - implemented: true, - kind: 'function', - modifiers: [], - name: 'get', - nodeType: 'FunctionDefinition', - overrides: null, - parameters: + documentation: null, + functionSelector: '6d4ce63c', + id: 32, + implemented: true, + kind: 'function', + modifiers: [], + name: 'get', + nodeType: 'FunctionDefinition', + overrides: null, + parameters: { id: 25, - nodeType: 'ParameterList', - parameters: [], - src: '175:2:0' }, - returnParameters: + nodeType: 'ParameterList', + parameters: [], + src: '175:2:0' }, + returnParameters: { id: 30, - nodeType: 'ParameterList', - parameters: [Array], - src: '193:16:0' }, - scope: 33, - src: '163:68:0', - stateMutability: 'nonpayable', - virtual: false, - visibility: 'public' } ], - scope: 34, - src: '0:233:0' + nodeType: 'ParameterList', + parameters: [Array], + src: '193:16:0' }, + scope: 33, + src: '163:68:0', + stateMutability: 'nonpayable', + virtual: false, + visibility: 'public' } ], + scope: 34, + src: '0:233:0' } ], - src: '0:233:0' + src: '0:233:0' } diff --git a/libs/remix-lib/README.md b/libs/remix-lib/README.md index 64a6706ef3..d4e0968bf4 100644 --- a/libs/remix-lib/README.md +++ b/libs/remix-lib/README.md @@ -43,7 +43,7 @@ Please feel free to open an issue or a pull request. -In case you want to add some code, do have a look to our contribution guidelnes [here](https://github.com/ethereum/remix-project/blob/master/CONTRIBUTING.md). Reach us on [Gitter](https://gitter.im/ethereum/remix) in case of any queries. +In case you want to add some code, do have a look at our contribution guidelines [here](https://github.com/ethereum/remix-project/blob/master/CONTRIBUTING.md). Reach us on [Gitter](https://gitter.im/ethereum/remix) in case of any queries. ### License -MIT © 2018-21 Remix Team \ No newline at end of file +MIT © 2018-21 Remix Team diff --git a/libs/remix-lib/package.json b/libs/remix-lib/package.json index 0f5de8f2e2..afec35ad63 100644 --- a/libs/remix-lib/package.json +++ b/libs/remix-lib/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-lib", - "version": "0.5.36", + "version": "0.5.40", "description": "Library to various Remix tools", "contributors": [ { @@ -52,6 +52,6 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme", "typings": "src/index.d.ts", - "gitHead": "bd494e84f12d18787433f25b7dea264c7b2063f8", + "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220", "types": "./src/index.d.ts" } \ No newline at end of file diff --git a/libs/remix-lib/src/execution/logsManager.ts b/libs/remix-lib/src/execution/logsManager.ts index 70e4ed9d41..a8ae3ec3c8 100644 --- a/libs/remix-lib/src/execution/logsManager.ts +++ b/libs/remix-lib/src/execution/logsManager.ts @@ -1,5 +1,6 @@ import { eachOf } from 'async' import { randomBytes } from 'crypto' +import { toChecksumAddress } from '@ethereumjs/util' export class LogsManager { notificationCallbacks @@ -22,8 +23,8 @@ export class LogsManager { web3.eth.getTransactionReceipt(txHash, (_error, receipt) => { for (const log of receipt.logs) { - this.oldLogs.push({ type: 'block', blockNumber, block, tx, log, txNumber: i }) - const subscriptions = this.getSubscriptionsFor({ type: 'block', blockNumber, block, tx, log }) + this.oldLogs.push({ type: 'block', blockNumber, block, tx, log, txNumber: i, receipt }) + const subscriptions = this.getSubscriptionsFor({ type: 'block', blockNumber, block, tx, log, receipt}) for (const subscriptionId of subscriptions) { const result = { @@ -55,15 +56,18 @@ export class LogsManager { if (queryFilter.topics.filter((logTopic) => changeEvent.log.topics.indexOf(logTopic) >= 0).length === 0) return false if (queryType === 'logs') { - const fromBlock = queryFilter.fromBlock || '0x0' - const toBlock = queryFilter.toBlock || this.oldLogs.length ? this.oldLogs[this.oldLogs.length - 1].blockNumber : '0x0' - if ((queryFilter.address === (changeEvent.tx.to || '').toString()) || queryFilter.address === (changeEvent.tx.getSenderAddress().toString())) { - if ((parseInt(toBlock) >= parseInt(changeEvent.blockNumber)) && (parseInt(fromBlock) <= parseInt(changeEvent.blockNumber))) { + const fromBlock = parseInt(queryFilter.fromBlock || '0x0') + let toBlock + if (queryFilter.toBlock === 'latest' || !queryFilter.toBlock) toBlock = Number.MAX_VALUE + else toBlock = parseInt(queryFilter.toBlock) + const targetAddress = toChecksumAddress(queryFilter.address) + if ((toBlock >= parseInt(changeEvent.blockNumber)) && (fromBlock <= parseInt(changeEvent.blockNumber))) { + if (changeEvent.log && changeEvent.log.address === targetAddress) { return true } } + return false } - return false } diff --git a/libs/remix-lib/src/execution/txExecution.ts b/libs/remix-lib/src/execution/txExecution.ts index 781d9733ce..267eb4de47 100644 --- a/libs/remix-lib/src/execution/txExecution.ts +++ b/libs/remix-lib/src/execution/txExecution.ts @@ -54,10 +54,11 @@ export function callFunction (from, to, data, value, gasLimit, funAbi, txRunner, /** * check if the vm has errored * - * @param {Object} execResult - execution result given by the VM + * @param {Object} execResult - execution result given by the VM, contain errorMessage and errorDate + * @param {Object} compiledContracts - Object containing contract compilation details * @return {Object} - { error: true/false, message: DOMNode } */ -export function checkVMError (execResult, compiledContracts) { +export function checkError (execResult, compiledContracts) { const errorCode = { OUT_OF_GAS: 'out of gas', STACK_UNDERFLOW: 'stack underflow', @@ -75,11 +76,11 @@ export function checkVMError (execResult, compiledContracts) { error: false, message: '' } - if (!execResult.exceptionError) { + if (!execResult.errorMessage) { return ret } - const exceptionError = execResult.exceptionError.error || '' - const error = `VM error: ${exceptionError}.\n` + const exceptionError = execResult.errorMessage || '' + const error = `Error occured: ${execResult.errorMessage}.\n` let msg if (exceptionError === errorCode.INVALID_OPCODE) { msg = '\t\n\tThe execution might have thrown.\n' @@ -87,8 +88,8 @@ export function checkVMError (execResult, compiledContracts) { } else if (exceptionError === errorCode.OUT_OF_GAS) { msg = '\tThe transaction ran out of gas. Please increase the Gas Limit.\n' ret.error = true - } else if (exceptionError === errorCode.REVERT) { - const returnData = execResult.returnValue + } else if (exceptionError === errorCode.REVERT || exceptionError === 'execution reverted') { + const returnData = execResult.errorData const returnDataHex = returnData.slice(2, 10) let customError if (compiledContracts) { @@ -172,4 +173,4 @@ export function checkVMError (execResult, compiledContracts) { } ret.message = `${error}\n${exceptionError}\n${msg}\nDebug the transaction to get more information.` return ret -} +} \ No newline at end of file diff --git a/libs/remix-lib/src/execution/txFormat.ts b/libs/remix-lib/src/execution/txFormat.ts index 86718cf207..de6ec91357 100644 --- a/libs/remix-lib/src/execution/txFormat.ts +++ b/libs/remix-lib/src/execution/txFormat.ts @@ -134,21 +134,21 @@ export function encodeConstructorCallAndLinkLibraries (contract, params, funAbi, */ export function linkLibraries (contract, linkLibraries, linkReferences, callback) { let bytecodeToDeploy = contract.evm.bytecode.object - if (bytecodeToDeploy.indexOf('_') >= 0) { - if (linkLibraries && linkReferences) { - for (const libFile in linkLibraries) { - for (const lib in linkLibraries[libFile]) { - const address = linkLibraries[libFile][lib] - if (!isValidAddress(address)) return callback(address + ' is not a valid address. Please check the provided address is valid.') - bytecodeToDeploy = linkLibraryStandardFromlinkReferences(lib, address.replace('0x', ''), bytecodeToDeploy, linkReferences) - } + if (bytecodeToDeploy.indexOf('_') >= 0) { + if (linkLibraries && linkReferences) { + for (const libFile in linkLibraries) { + for (const lib in linkLibraries[libFile]) { + const address = linkLibraries[libFile][lib] + if (!isValidAddress(address)) return callback(address + ' is not a valid address. Please check the provided address is valid.') + bytecodeToDeploy = linkLibraryStandardFromlinkReferences(lib, address.replace('0x', ''), bytecodeToDeploy, linkReferences) } } } - if (bytecodeToDeploy.indexOf('_') >= 0) { - return callback('Failed to link some libraries') - } - return callback(null, bytecodeToDeploy) + } + if (bytecodeToDeploy.indexOf('_') >= 0) { + return callback('Failed to link some libraries') + } + return callback(null, bytecodeToDeploy) } /** @@ -459,7 +459,7 @@ export function parseFunctionParams (params) { args.push(parseFunctionParams(params.substring(i + 1, j))) i = j - 1 } else if (params.charAt(i) === ',' || i === params.length - 1) { // , or end of string - // if startIndex >= 0, it means a parameter was being parsed, it can be first or other parameter + // if startIndex >= 0, it means a parameter was being parsed, it can be first or other parameter if (startIndex >= 0) { let param = params.substring(startIndex, i === params.length - 1 ? undefined : i) param = normalizeParam(param) diff --git a/libs/remix-lib/src/execution/txListener.ts b/libs/remix-lib/src/execution/txListener.ts index 960ca63a55..d4251f0297 100644 --- a/libs/remix-lib/src/execution/txListener.ts +++ b/libs/remix-lib/src/execution/txListener.ts @@ -36,7 +36,7 @@ export class TxListener { constructor (opt, executionContext) { this.event = new EventManager() - // has a default for now for backwards compatability + // has a default for now for backwards compatibility this.executionContext = executionContext this._api = opt.api this._resolvedTransactions = {} diff --git a/libs/remix-lib/src/execution/txRunnerVM.ts b/libs/remix-lib/src/execution/txRunnerVM.ts index 5a800e2326..31364c045a 100644 --- a/libs/remix-lib/src/execution/txRunnerVM.ts +++ b/libs/remix-lib/src/execution/txRunnerVM.ts @@ -34,7 +34,7 @@ export class TxRunnerVM { constructor (vmaccounts, api, getVMObject) { this.event = new EventManager() this.logsManager = new LogsManager() - // has a default for now for backwards compatability + // has a default for now for backwards compatibility this.getVMObject = getVMObject this.commonContext = this.getVMObject().common this.blockNumber = 0 diff --git a/libs/remix-lib/src/execution/txRunnerWeb3.ts b/libs/remix-lib/src/execution/txRunnerWeb3.ts index d5fce39b92..ab754c0fef 100644 --- a/libs/remix-lib/src/execution/txRunnerWeb3.ts +++ b/libs/remix-lib/src/execution/txRunnerWeb3.ts @@ -107,13 +107,13 @@ export class TxRunnerWeb3 { console.log(errNetWork) return } - const txCopy = { ...tx, type: undefined, maxFeePerGas: undefined, gasPrice: undefined } + const txCopy = { ...tx, type: undefined, maxFeePerGas: undefined, gasPrice: undefined } if (network && network.lastBlock) { if (network.lastBlock.baseFeePerGas) { // the sending stack (web3.js / metamask need to have the type defined) // this is to avoid the following issue: https://github.com/MetaMask/metamask-extension/issues/11824 txCopy.type = '0x2' - txCopy.maxFeePerGas = Math.ceil(network.lastBlock.baseFeePerGas + network.lastBlock.baseFeePerGas / 2) + txCopy.maxFeePerGas = Math.ceil(network.lastBlock.baseFeePerGas + network.lastBlock.baseFeePerGas / 3) } else { txCopy.type = '0x1' txCopy.gasPrice = network.lastBlock.baseFeePerGas diff --git a/libs/remix-lib/src/hash.ts b/libs/remix-lib/src/hash.ts index b7d56237b1..624154be99 100644 --- a/libs/remix-lib/src/hash.ts +++ b/libs/remix-lib/src/hash.ts @@ -10,22 +10,22 @@ import { toBuffer, setLengthLeft, isHexString } from '@ethereumjs/util' */ export const keccak = function(a: Buffer, bits: number = 256): Buffer { assertIsBuffer(a) - switch (bits) { - case 224: { - return toBuffer(keccak224(a)) - } - case 256: { - return toBuffer(k256(a)) - } - case 384: { - return toBuffer(keccak384(a)) - } - case 512: { - return toBuffer(keccak512(a)) - } - default: { - throw new Error(`Invald algorithm: keccak${bits}`) - } + switch (bits) { + case 224: { + return toBuffer(keccak224(a)) + } + case 256: { + return toBuffer(k256(a)) + } + case 384: { + return toBuffer(keccak384(a)) + } + case 512: { + return toBuffer(keccak512(a)) + } + default: { + throw new Error(`Invald algorithm: keccak${bits}`) + } } } diff --git a/libs/remix-lib/src/util.ts b/libs/remix-lib/src/util.ts index 205488c941..f28d6c80c0 100644 --- a/libs/remix-lib/src/util.ts +++ b/libs/remix-lib/src/util.ts @@ -203,7 +203,9 @@ export function inputParametersExtraction () { } export function extractcborMetadata (value) { - return value.replace(cborEncodedValueExtraction(), '') + const cbor = value.match(cborEncodedValueExtraction()) + if (cbor && cbor[0]) value = value.replace(cbor[0], '') + return value } export function extractSwarmHash (value) { @@ -214,7 +216,9 @@ export function extractSwarmHash (value) { } export function extractinputParameters (value) { - return value.replace(inputParametersExtraction(), '') + const inputsParam = getinputParameters(value) + if (inputsParam) value = value.replace(inputsParam, '') + return value } export function getinputParameters (value) { @@ -222,7 +226,7 @@ export function getinputParameters (value) { if (regex && regex[1]) { return regex[1] } else - return '' + return '' } /** diff --git a/libs/remix-lib/test/txFormat.ts b/libs/remix-lib/test/txFormat.ts index 41ada91d24..4203d452e5 100644 --- a/libs/remix-lib/test/txFormat.ts +++ b/libs/remix-lib/test/txFormat.ts @@ -183,7 +183,7 @@ tape('ContractParameters - (TxFormat.buildData) - link Libraries', function (t) function testLinkLibrary (st, fakeDeployedContracts, callbackDeployLibraries) { const deployMsg = ['creation of library test.sol:lib1 pending...', - 'creation of library test.sol:lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2 pending...'] + 'creation of library test.sol:lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2 pending...'] txFormat.buildData('testContractLinkLibrary', context.contract, context.output.contracts, true, context.contract.abi[0], '', (error, data) => { if (error) { return st.fail(error) } console.log(data) @@ -212,7 +212,7 @@ function testLinkLibrary2 (st, callbackDeployLibraries) { const data = '608060405234801561001057600080fd5b506101e2806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80636d4ce63c14610030575b600080fd5b61003861003a565b005b73f7a10e525d4b168f45f74db1b61f63d3e7619e116344733ae16040518163ffffffff1660e01b815260040160006040518083038186803b15801561007e57600080fd5b505af4158015610092573d6000803e3d6000fd5b5050505073f7a10e525d4b168f45f74db1b61f63d3e7619e336344733ae16040518163ffffffff1660e01b815260040160006040518083038186803b1580156100da57600080fd5b505af41580156100ee573d6000803e3d6000fd5b5050505073f7a10e525d4b168f45f74db1b61f63d3e7619e336344733ae16040518163ffffffff1660e01b815260040160006040518083038186803b15801561013657600080fd5b505af415801561014a573d6000803e3d6000fd5b5050505073f7a10e525d4b168f45f74db1b61f63d3e7619e116344733ae16040518163ffffffff1660e01b815260040160006040518083038186803b15801561019257600080fd5b505af41580156101a6573d6000803e3d6000fd5b5050505056fea264697066735822122007784c53df7f324243100f6642d889a08a88831c3811dd13eebe3163b7eb2e5464736f6c63430006000033' const deployMsg = ['creation of library test.sol:lib1 pending...', - 'creation of library test.sol:lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2 pending...'] + 'creation of library test.sol:lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2 pending...'] txFormat.encodeConstructorCallAndLinkLibraries(context.contract, '', context.contract.abi[0], librariesReference, context.contract.evm.bytecode.linkReferences, (error, result) => { console.log(error, result) st.equal(data, result.dataHex) diff --git a/libs/remix-lib/test/util.ts b/libs/remix-lib/test/util.ts index 2f4b63926a..61f31e0a9d 100644 --- a/libs/remix-lib/test/util.ts +++ b/libs/remix-lib/test/util.ts @@ -113,6 +113,11 @@ const uniswapQuote2 = `0x608060405234801561001057600080fd5b506004361061007d57600 const uniswapQuote1 = `0x608060405234801561001057600080fd5b506004361061007d5760003560e01c8063c45a01551161005b578063c45a0155146100d3578063cdca1753146100db578063f7729d43146100ee578063fa461e33146101015761007d565b80632f80bb1d1461008257806330d07f21146100ab5780634aa4a4fc146100be575b600080fd5b610095610090366004610e9e565b610116565b6040516100a29190611148565b60405180910390f35b6100956100b9366004610e30565b61017b565b6100c6610340565b6040516100a29190611084565b6100c6610364565b6100956100e9366004610e9e565b610388565b6100956100fc366004610e30565b6103d6565b61011461010f366004610f04565b610555565b005b60005b600061012484610660565b9050600080600061013487610668565b92509250925061014882848389600061017b565b955083156101605761015987610699565b965061016c565b85945050505050610175565b50505050610119565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff808616878216109083166101a65760008490555b6101b18787876106ce565b73ffffffffffffffffffffffffffffffffffffffff1663128acb0830836101d78861070c565b60000373ffffffffffffffffffffffffffffffffffffffff8816156101fc5787610222565b8561021b5773fffd8963efd1fc6a506488495d951d5263988d25610222565b6401000276a45b8b8b8e6040516020016102379392919061101e565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016102669594939291906110a5565b6040805180830381600087803b15801561027f57600080fd5b505af19250505080156102cd575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526102ca91810190610ee1565b60015b610333573d8080156102fb576040519150601f19603f3d011682016040523d82523d6000602084013e610300565b606091505b5073ffffffffffffffffffffffffffffffffffffffff841661032157600080555b61032a8161073e565b92505050610337565b5050505b95945050505050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b7f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98481565b60005b600061039684610660565b905060008060006103a687610668565b9250925092506103ba8383838960006103d6565b95508315610160576103cb87610699565b96505050505061038b565b600073ffffffffffffffffffffffffffffffffffffffff808616908716106103ff8787876106ce565b73ffffffffffffffffffffffffffffffffffffffff1663128acb0830836104258861070c565b73ffffffffffffffffffffffffffffffffffffffff881615610447578761046d565b856104665773fffd8963efd1fc6a506488495d951d5263988d2561046d565b6401000276a45b8c8b8d6040516020016104829392919061101e565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016104b19594939291906110a5565b6040805180830381600087803b1580156104ca57600080fd5b505af1925050508015610518575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261051591810190610ee1565b60015b610333573d808015610546576040519150601f19603f3d011682016040523d82523d6000602084013e61054b565b606091505b5061032a8161073e565b60008313806105645750600082135b61056d57600080fd5b600080600061057b84610668565b9250925092506105ad7f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f9848484846107ef565b5060008060008089136105f3578573ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1610888a600003610628565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161089896000035b925092509250821561063f57604051818152602081fd5b6000541561065557600054811461065557600080fd5b604051828152602081fd5b516042111590565b600080806106768482610805565b9250610683846014610905565b9050610690846017610805565b91509193909250565b80516060906101759083906017907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe9016109f5565b60006107047f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f9846106ff868686610bdc565b610c59565b949350505050565b60007f8000000000000000000000000000000000000000000000000000000000000000821061073a57600080fd5b5090565b600081516020146107db5760448251101561078e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161078590611111565b60405180910390fd5b600482019150818060200190518101906107a89190610f52565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161078591906110f7565b818060200190518101906101759190610fbc565b600061033785610800868686610bdc565b610d8f565b60008182601401101561087957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f746f416464726573735f6f766572666c6f770000000000000000000000000000604482015290519081900360640190fd5b81601401835110156108ec57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f416464726573735f6f75744f66426f756e64730000000000000000000000604482015290519081900360640190fd5b5001602001516c01000000000000000000000000900490565b60008182600301101561097957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f746f55696e7432345f6f766572666c6f77000000000000000000000000000000604482015290519081900360640190fd5b81600301835110156109ec57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f746f55696e7432345f6f75744f66426f756e6473000000000000000000000000604482015290519081900360640190fd5b50016003015190565b60608182601f011015610a6957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b828284011015610ada57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b81830184511015610b4c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015290519081900360640190fd5b606082158015610b6b5760405191506000825260208201604052610bd3565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015610ba4578051835260209283019201610b8c565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b610be4610dbf565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161115610c1c579192915b506040805160608101825273ffffffffffffffffffffffffffffffffffffffff948516815292909316602083015262ffffff169181019190915290565b6000816020015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff1610610c9b57600080fd5b508051602080830151604093840151845173ffffffffffffffffffffffffffffffffffffffff94851681850152939091168385015262ffffff166060808401919091528351808403820181526080840185528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a085015294901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a183015260b58201939093527fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b5460d5808301919091528251808303909101815260f5909101909152805191012090565b6000610d9b8383610c59565b90503373ffffffffffffffffffffffffffffffffffffffff82161461017557600080fd5b604080516060810182526000808252602082018190529181019190915290565b600082601f830112610def578081fd5b8135610e02610dfd82611175565b611151565b818152846020838601011115610e16578283fd5b816020850160208301379081016020019190915292915050565b600080600080600060a08688031215610e47578081fd5b8535610e52816111e5565b94506020860135610e62816111e5565b9350604086013562ffffff81168114610e79578182fd5b9250606086013591506080860135610e90816111e5565b809150509295509295909350565b60008060408385031215610eb0578182fd5b823567ffffffffffffffff811115610ec6578283fd5b610ed285828601610ddf565b95602094909401359450505050565b60008060408385031215610ef3578182fd5b505080516020909101519092909150565b600080600060608486031215610f18578283fd5b8335925060208401359150604084013567ffffffffffffffff811115610f3c578182fd5b610f4886828701610ddf565b9150509250925092565b600060208284031215610f63578081fd5b815167ffffffffffffffff811115610f79578182fd5b8201601f81018413610f89578182fd5b8051610f97610dfd82611175565b818152856020838501011115610fab578384fd5b6103378260208301602086016111b5565b600060208284031215610fcd578081fd5b5051919050565b60008151808452610fec8160208601602086016111b5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b606093841b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116825260e89390931b7fffffff0000000000000000000000000000000000000000000000000000000000166014820152921b166017820152602b0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600073ffffffffffffffffffffffffffffffffffffffff8088168352861515602084015285604084015280851660608401525060a060808301526110ec60a0830184610fd4565b979650505050505050565b60006020825261110a6020830184610fd4565b9392505050565b60208082526010908201527f556e6578706563746564206572726f7200000000000000000000000000000000604082015260600190565b90815260200190565b60405181810167ffffffffffffffff8111828210171561116d57fe5b604052919050565b600067ffffffffffffffff82111561118957fe5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b838110156111d05781810151838201526020016111b8565b838111156111df576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461120757600080fd5b5056fea164736f6c6343000706000a` +tape('util.compareByteCode which have input parameters', function (t) { + t.plan(1) + t.ok(util.compareByteCode(contractWithParameters, contractWithoutParameters), 'same contract but different parameters should still match "comparebytecode"') +}) +const contractWithParameters = `0x608060405234801562000010575f80fd5b5060405162001756380380620017568339818101604052810190620000369190620001e7565b8160039081620000479190620004a1565b508060049081620000599190620004a1565b50505062000585565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c3826200007b565b810181811067ffffffffffffffff82111715620000e557620000e46200008b565b5b80604052505050565b5f620000f962000062565b9050620001078282620000b8565b919050565b5f67ffffffffffffffff8211156200012957620001286200008b565b5b62000134826200007b565b9050602081019050919050565b5f5b838110156200016057808201518184015260208101905062000143565b5f8484015250505050565b5f620001816200017b846200010c565b620000ee565b905082815260208101848484011115620001a0576200019f62000077565b5b620001ad84828562000141565b509392505050565b5f82601f830112620001cc57620001cb62000073565b5b8151620001de8482602086016200016b565b91505092915050565b5f80604083850312156200020057620001ff6200006b565b5b5f83015167ffffffffffffffff81111562000220576200021f6200006f565b5b6200022e85828601620001b5565b925050602083015167ffffffffffffffff8111156200025257620002516200006f565b5b6200026085828601620001b5565b9150509250929050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620002b957607f821691505b602082108103620002cf57620002ce62000274565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003337fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002f6565b6200033f8683620002f6565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000389620003836200037d8462000357565b62000360565b62000357565b9050919050565b5f819050919050565b620003a48362000369565b620003bc620003b38262000390565b84845462000302565b825550505050565b5f90565b620003d2620003c4565b620003df81848462000399565b505050565b5b818110156200040657620003fa5f82620003c8565b600181019050620003e5565b5050565b601f82111562000455576200041f81620002d5565b6200042a84620002e7565b810160208510156200043a578190505b620004526200044985620002e7565b830182620003e4565b50505b505050565b5f82821c905092915050565b5f620004775f19846008026200045a565b1980831691505092915050565b5f62000491838362000466565b9150826002028217905092915050565b620004ac826200026a565b67ffffffffffffffff811115620004c857620004c76200008b565b5b620004d48254620002a1565b620004e18282856200040a565b5f60209050601f83116001811462000517575f841562000502578287015190505b6200050e858262000484565b8655506200057d565b601f1984166200052786620002d5565b5f5b82811015620005505784890151825560018201915060208501945060208101905062000529565b868310156200057057848901516200056c601f89168262000466565b8355505b6001600288020188555050505b505050505050565b6111c380620005935f395ff3fe608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063395093511161006f578063395093511461016557806370a082311461019557806395d89b41146101c5578063a457c2d7146101e3578063a9059cbb14610213578063dd62ed3e14610243576100a7565b806306fdde03146100ab578063095ea7b3146100c957806318160ddd146100f957806323b872dd14610117578063313ce56714610147575b5f80fd5b6100b3610273565b6040516100c09190610add565b60405180910390f35b6100e360048036038101906100de9190610b8e565b610303565b6040516100f09190610be6565b60405180910390f35b610101610325565b60405161010e9190610c0e565b60405180910390f35b610131600480360381019061012c9190610c27565b61032e565b60405161013e9190610be6565b60405180910390f35b61014f61035c565b60405161015c9190610c92565b60405180910390f35b61017f600480360381019061017a9190610b8e565b610364565b60405161018c9190610be6565b60405180910390f35b6101af60048036038101906101aa9190610cab565b61039a565b6040516101bc9190610c0e565b60405180910390f35b6101cd6103df565b6040516101da9190610add565b60405180910390f35b6101fd60048036038101906101f89190610b8e565b61046f565b60405161020a9190610be6565b60405180910390f35b61022d60048036038101906102289190610b8e565b6104e4565b60405161023a9190610be6565b60405180910390f35b61025d60048036038101906102589190610cd6565b610506565b60405161026a9190610c0e565b60405180910390f35b60606003805461028290610d41565b80601f01602080910402602001604051908101604052809291908181526020018280546102ae90610d41565b80156102f95780601f106102d0576101008083540402835291602001916102f9565b820191905f5260205f20905b8154815290600101906020018083116102dc57829003601f168201915b5050505050905090565b5f8061030d610588565b905061031a81858561058f565b600191505092915050565b5f600254905090565b5f80610338610588565b9050610345858285610752565b6103508585856107dd565b60019150509392505050565b5f6012905090565b5f8061036e610588565b905061038f8185856103808589610506565b61038a9190610d9e565b61058f565b600191505092915050565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6060600480546103ee90610d41565b80601f016020809104026020016040519081016040528092919081815260200182805461041a90610d41565b80156104655780601f1061043c57610100808354040283529160200191610465565b820191905f5260205f20905b81548152906001019060200180831161044857829003601f168201915b5050505050905090565b5f80610479610588565b90505f6104868286610506565b9050838110156104cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104c290610e41565b60405180910390fd5b6104d8828686840361058f565b60019250505092915050565b5f806104ee610588565b90506104fb8185856107dd565b600191505092915050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036105fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105f490610ecf565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361066b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161066290610f5d565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516107459190610c0e565b60405180910390a3505050565b5f61075d8484610506565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146107d757818110156107c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c090610fc5565b60405180910390fd5b6107d6848484840361058f565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361084b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161084290611053565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036108b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108b0906110e1565b60405180910390fd5b6108c4838383610a49565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015610947576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093e9061116f565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550815f808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610a309190610c0e565b60405180910390a3610a43848484610a4e565b50505050565b505050565b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610a8a578082015181840152602081019050610a6f565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610aaf82610a53565b610ab98185610a5d565b9350610ac9818560208601610a6d565b610ad281610a95565b840191505092915050565b5f6020820190508181035f830152610af58184610aa5565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610b2a82610b01565b9050919050565b610b3a81610b20565b8114610b44575f80fd5b50565b5f81359050610b5581610b31565b92915050565b5f819050919050565b610b6d81610b5b565b8114610b77575f80fd5b50565b5f81359050610b8881610b64565b92915050565b5f8060408385031215610ba457610ba3610afd565b5b5f610bb185828601610b47565b9250506020610bc285828601610b7a565b9150509250929050565b5f8115159050919050565b610be081610bcc565b82525050565b5f602082019050610bf95f830184610bd7565b92915050565b610c0881610b5b565b82525050565b5f602082019050610c215f830184610bff565b92915050565b5f805f60608486031215610c3e57610c3d610afd565b5b5f610c4b86828701610b47565b9350506020610c5c86828701610b47565b9250506040610c6d86828701610b7a565b9150509250925092565b5f60ff82169050919050565b610c8c81610c77565b82525050565b5f602082019050610ca55f830184610c83565b92915050565b5f60208284031215610cc057610cbf610afd565b5b5f610ccd84828501610b47565b91505092915050565b5f8060408385031215610cec57610ceb610afd565b5b5f610cf985828601610b47565b9250506020610d0a85828601610b47565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680610d5857607f821691505b602082108103610d6b57610d6a610d14565b5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610da882610b5b565b9150610db383610b5b565b9250828201905080821115610dcb57610dca610d71565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f775f8201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b5f610e2b602583610a5d565b9150610e3682610dd1565b604082019050919050565b5f6020820190508181035f830152610e5881610e1f565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f206164645f8201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b5f610eb9602483610a5d565b9150610ec482610e5f565b604082019050919050565b5f6020820190508181035f830152610ee681610ead565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f2061646472655f8201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b5f610f47602283610a5d565b9150610f5282610eed565b604082019050919050565b5f6020820190508181035f830152610f7481610f3b565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000005f82015250565b5f610faf601d83610a5d565b9150610fba82610f7b565b602082019050919050565b5f6020820190508181035f830152610fdc81610fa3565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f2061645f8201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b5f61103d602583610a5d565b915061104882610fe3565b604082019050919050565b5f6020820190508181035f83015261106a81611031565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f6110cb602383610a5d565b91506110d682611071565b604082019050919050565b5f6020820190508181035f8301526110f8816110bf565b9050919050565b7f45524332303a207472616e7366657220616d6f756e74206578636565647320625f8201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b5f611159602683610a5d565b9150611164826110ff565b604082019050919050565b5f6020820190508181035f8301526111868161114d565b905091905056fea264697066735822122068e7088e2020b3a92aeb07338de801db3c8164bac57255e32c1c6a6614fdeabe64736f6c63430008150033000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017900000000000000000000000000000000000000000000000000000000000000` - +const contractWithoutParameters = `0x608060405234801562000010575f80fd5b5060405162001756380380620017568339818101604052810190620000369190620001e7565b8160039081620000479190620004a1565b508060049081620000599190620004a1565b50505062000585565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c3826200007b565b810181811067ffffffffffffffff82111715620000e557620000e46200008b565b5b80604052505050565b5f620000f962000062565b9050620001078282620000b8565b919050565b5f67ffffffffffffffff8211156200012957620001286200008b565b5b62000134826200007b565b9050602081019050919050565b5f5b838110156200016057808201518184015260208101905062000143565b5f8484015250505050565b5f620001816200017b846200010c565b620000ee565b905082815260208101848484011115620001a0576200019f62000077565b5b620001ad84828562000141565b509392505050565b5f82601f830112620001cc57620001cb62000073565b5b8151620001de8482602086016200016b565b91505092915050565b5f80604083850312156200020057620001ff6200006b565b5b5f83015167ffffffffffffffff81111562000220576200021f6200006f565b5b6200022e85828601620001b5565b925050602083015167ffffffffffffffff8111156200025257620002516200006f565b5b6200026085828601620001b5565b9150509250929050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620002b957607f821691505b602082108103620002cf57620002ce62000274565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003337fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002f6565b6200033f8683620002f6565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000389620003836200037d8462000357565b62000360565b62000357565b9050919050565b5f819050919050565b620003a48362000369565b620003bc620003b38262000390565b84845462000302565b825550505050565b5f90565b620003d2620003c4565b620003df81848462000399565b505050565b5b818110156200040657620003fa5f82620003c8565b600181019050620003e5565b5050565b601f82111562000455576200041f81620002d5565b6200042a84620002e7565b810160208510156200043a578190505b620004526200044985620002e7565b830182620003e4565b50505b505050565b5f82821c905092915050565b5f620004775f19846008026200045a565b1980831691505092915050565b5f62000491838362000466565b9150826002028217905092915050565b620004ac826200026a565b67ffffffffffffffff811115620004c857620004c76200008b565b5b620004d48254620002a1565b620004e18282856200040a565b5f60209050601f83116001811462000517575f841562000502578287015190505b6200050e858262000484565b8655506200057d565b601f1984166200052786620002d5565b5f5b82811015620005505784890151825560018201915060208501945060208101905062000529565b868310156200057057848901516200056c601f89168262000466565b8355505b6001600288020188555050505b505050505050565b6111c380620005935f395ff3fe608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063395093511161006f578063395093511461016557806370a082311461019557806395d89b41146101c5578063a457c2d7146101e3578063a9059cbb14610213578063dd62ed3e14610243576100a7565b806306fdde03146100ab578063095ea7b3146100c957806318160ddd146100f957806323b872dd14610117578063313ce56714610147575b5f80fd5b6100b3610273565b6040516100c09190610add565b60405180910390f35b6100e360048036038101906100de9190610b8e565b610303565b6040516100f09190610be6565b60405180910390f35b610101610325565b60405161010e9190610c0e565b60405180910390f35b610131600480360381019061012c9190610c27565b61032e565b60405161013e9190610be6565b60405180910390f35b61014f61035c565b60405161015c9190610c92565b60405180910390f35b61017f600480360381019061017a9190610b8e565b610364565b60405161018c9190610be6565b60405180910390f35b6101af60048036038101906101aa9190610cab565b61039a565b6040516101bc9190610c0e565b60405180910390f35b6101cd6103df565b6040516101da9190610add565b60405180910390f35b6101fd60048036038101906101f89190610b8e565b61046f565b60405161020a9190610be6565b60405180910390f35b61022d60048036038101906102289190610b8e565b6104e4565b60405161023a9190610be6565b60405180910390f35b61025d60048036038101906102589190610cd6565b610506565b60405161026a9190610c0e565b60405180910390f35b60606003805461028290610d41565b80601f01602080910402602001604051908101604052809291908181526020018280546102ae90610d41565b80156102f95780601f106102d0576101008083540402835291602001916102f9565b820191905f5260205f20905b8154815290600101906020018083116102dc57829003601f168201915b5050505050905090565b5f8061030d610588565b905061031a81858561058f565b600191505092915050565b5f600254905090565b5f80610338610588565b9050610345858285610752565b6103508585856107dd565b60019150509392505050565b5f6012905090565b5f8061036e610588565b905061038f8185856103808589610506565b61038a9190610d9e565b61058f565b600191505092915050565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6060600480546103ee90610d41565b80601f016020809104026020016040519081016040528092919081815260200182805461041a90610d41565b80156104655780601f1061043c57610100808354040283529160200191610465565b820191905f5260205f20905b81548152906001019060200180831161044857829003601f168201915b5050505050905090565b5f80610479610588565b90505f6104868286610506565b9050838110156104cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104c290610e41565b60405180910390fd5b6104d8828686840361058f565b60019250505092915050565b5f806104ee610588565b90506104fb8185856107dd565b600191505092915050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036105fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105f490610ecf565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361066b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161066290610f5d565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516107459190610c0e565b60405180910390a3505050565b5f61075d8484610506565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146107d757818110156107c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c090610fc5565b60405180910390fd5b6107d6848484840361058f565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361084b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161084290611053565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036108b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108b0906110e1565b60405180910390fd5b6108c4838383610a49565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015610947576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093e9061116f565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550815f808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610a309190610c0e565b60405180910390a3610a43848484610a4e565b50505050565b505050565b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610a8a578082015181840152602081019050610a6f565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610aaf82610a53565b610ab98185610a5d565b9350610ac9818560208601610a6d565b610ad281610a95565b840191505092915050565b5f6020820190508181035f830152610af58184610aa5565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610b2a82610b01565b9050919050565b610b3a81610b20565b8114610b44575f80fd5b50565b5f81359050610b5581610b31565b92915050565b5f819050919050565b610b6d81610b5b565b8114610b77575f80fd5b50565b5f81359050610b8881610b64565b92915050565b5f8060408385031215610ba457610ba3610afd565b5b5f610bb185828601610b47565b9250506020610bc285828601610b7a565b9150509250929050565b5f8115159050919050565b610be081610bcc565b82525050565b5f602082019050610bf95f830184610bd7565b92915050565b610c0881610b5b565b82525050565b5f602082019050610c215f830184610bff565b92915050565b5f805f60608486031215610c3e57610c3d610afd565b5b5f610c4b86828701610b47565b9350506020610c5c86828701610b47565b9250506040610c6d86828701610b7a565b9150509250925092565b5f60ff82169050919050565b610c8c81610c77565b82525050565b5f602082019050610ca55f830184610c83565b92915050565b5f60208284031215610cc057610cbf610afd565b5b5f610ccd84828501610b47565b91505092915050565b5f8060408385031215610cec57610ceb610afd565b5b5f610cf985828601610b47565b9250506020610d0a85828601610b47565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680610d5857607f821691505b602082108103610d6b57610d6a610d14565b5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610da882610b5b565b9150610db383610b5b565b9250828201905080821115610dcb57610dca610d71565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f775f8201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b5f610e2b602583610a5d565b9150610e3682610dd1565b604082019050919050565b5f6020820190508181035f830152610e5881610e1f565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f206164645f8201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b5f610eb9602483610a5d565b9150610ec482610e5f565b604082019050919050565b5f6020820190508181035f830152610ee681610ead565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f2061646472655f8201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b5f610f47602283610a5d565b9150610f5282610eed565b604082019050919050565b5f6020820190508181035f830152610f7481610f3b565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000005f82015250565b5f610faf601d83610a5d565b9150610fba82610f7b565b602082019050919050565b5f6020820190508181035f830152610fdc81610fa3565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f2061645f8201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b5f61103d602583610a5d565b915061104882610fe3565b604082019050919050565b5f6020820190508181035f83015261106a81611031565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f6110cb602383610a5d565b91506110d682611071565b604082019050919050565b5f6020820190508181035f8301526110f8816110bf565b9050919050565b7f45524332303a207472616e7366657220616d6f756e74206578636565647320625f8201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b5f611159602683610a5d565b9150611164826110ff565b604082019050919050565b5f6020820190508181035f8301526111868161114d565b905091905056fea264697066735822122068e7088e2020b3a92aeb07338de801db3c8164bac57255e32c1c6a6614fdeabe64736f6c63430008150033` \ No newline at end of file diff --git a/libs/remix-simulator/README.md b/libs/remix-simulator/README.md index bf1b0c675a..8410dd63f0 100644 --- a/libs/remix-simulator/README.md +++ b/libs/remix-simulator/README.md @@ -86,7 +86,7 @@ Please feel free to open an issue or a pull request. -In case you want to add some code, do have a look to our contribution guidelnes [here](https://github.com/ethereum/remix-project/blob/master/CONTRIBUTING.md). Reach us on [Gitter](https://gitter.im/ethereum/remix) in case of any queries. +In case you want to add some code, do have a look at our contribution guidelines [here](https://github.com/ethereum/remix-project/blob/master/CONTRIBUTING.md). Reach us on [Gitter](https://gitter.im/ethereum/remix) in case of any queries. ### License -MIT © 2018-21 Remix Team \ No newline at end of file +MIT © 2018-21 Remix Team diff --git a/libs/remix-simulator/bin/ethsim b/libs/remix-simulator/bin/ethsim index 607cabbe9c..814e2a6a46 100755 --- a/libs/remix-simulator/bin/ethsim +++ b/libs/remix-simulator/bin/ethsim @@ -26,14 +26,19 @@ program .option('-c, --coinbase [coinbase]', 'specify coinbase', '0x0000000000000000000000000000000000000000') .option('--rpc', 'run rpc server only', true) .option('--details', 'display payloads for every requests and their responses', false) - .action(() => { + .action((option) => { + console.log('coinbase: ', option.coinbase) + console.log('rpc: ', option.rpc) + console.log('details: ', option.details) + console.log('host: ', option.ip) + console.log('port: ', option.port) const Server = require('../src/server') const server = new Server({ - coinbase: program.coinbase, - rpc: program.rpc, - logDetails: program.details + coinbase: option.coinbase, + rpc: option.rpc, + logDetails: option.details }) - server.start(program.host, program.port) + server.start(option.ip, option.port) }) program.parse(process.argv) diff --git a/libs/remix-simulator/package.json b/libs/remix-simulator/package.json index 6d08d339c9..594f82c8f2 100644 --- a/libs/remix-simulator/package.json +++ b/libs/remix-simulator/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-simulator", - "version": "0.2.29", + "version": "0.2.33", "description": "Ethereum IDE and tools for the web", "contributors": [ { @@ -22,7 +22,7 @@ "@ethereumjs/tx": "^4.1.1", "@ethereumjs/util": "^8.0.5", "@ethereumjs/vm": "^6.4.1", - "@remix-project/remix-lib": "^0.5.36", + "@remix-project/remix-lib": "^0.5.40", "ansi-gray": "^0.1.1", "async": "^3.1.0", "body-parser": "^1.18.2", @@ -67,6 +67,6 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme", "typings": "src/index.d.ts", - "gitHead": "bd494e84f12d18787433f25b7dea264c7b2063f8", + "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220", "types": "./src/index.d.ts" } \ No newline at end of file diff --git a/libs/remix-simulator/src/VmProxy.ts b/libs/remix-simulator/src/VmProxy.ts index a0005f8fa2..90d7ebfbf7 100644 --- a/libs/remix-simulator/src/VmProxy.ts +++ b/libs/remix-simulator/src/VmProxy.ts @@ -182,7 +182,7 @@ export class VmProxy { topics.push('0x') } logs.push({ - address: '0x' + log[0].toString('hex'), + address: toChecksumAddress('0x' + log[0].toString('hex')), data: '0x' + log[2].toString('hex'), topics: topics, rawVMResponse: log diff --git a/libs/remix-simulator/src/methods/blocks.ts b/libs/remix-simulator/src/methods/blocks.ts index cfd8c30ef4..60b47bab25 100644 --- a/libs/remix-simulator/src/methods/blocks.ts +++ b/libs/remix-simulator/src/methods/blocks.ts @@ -43,25 +43,25 @@ export class Blocks { } const transactions = block.transactions.map((t) => { - const hash = '0x' + t.hash().toString('hex') - const tx = this.vmContext.txByHash[hash] - const receipt = this.vmContext.currentVm.web3vm.txsReceipt[hash] - if (receipt) { - return { - blockHash: '0x' + block.hash().toString('hex'), - blockNumber: bigIntToHex(block.header.number), - from: receipt.from, - gas: bigIntToHex(receipt.gas), - chainId: '0xd05', - gasPrice: '0x4a817c800', // 20000000000 - hash: receipt.transactionHash, - input: receipt.input, - nonce: bigIntToHex(tx.nonce), - transactionIndex: this.TX_INDEX, - value: bigIntToHex(tx.value), - to: receipt.to ? receipt.to : null + const hash = '0x' + t.hash().toString('hex') + const tx = this.vmContext.txByHash[hash] + const receipt = this.vmContext.currentVm.web3vm.txsReceipt[hash] + if (receipt) { + return { + blockHash: '0x' + block.hash().toString('hex'), + blockNumber: bigIntToHex(block.header.number), + from: receipt.from, + gas: bigIntToHex(receipt.gas), + chainId: '0xd05', + gasPrice: '0x4a817c800', // 20000000000 + hash: receipt.transactionHash, + input: receipt.input, + nonce: bigIntToHex(tx.nonce), + transactionIndex: this.TX_INDEX, + value: bigIntToHex(tx.value), + to: receipt.to ? receipt.to : null + } } - } }) const b = { baseFeePerGas: '0x01', @@ -101,22 +101,22 @@ export class Blocks { const tx = this.vmContext.txByHash[hash] const receipt = this.vmContext.currentVm.web3vm.txsReceipt[hash] if (receipt) { - return { - blockHash: '0x' + block.hash().toString('hex'), - blockNumber: bigIntToHex(block.header.number), - from: receipt.from, - gas: toHex(receipt.gas), - chainId: '0xd05', - gasPrice: '0x4a817c800', // 20000000000 - hash: receipt.transactionHash, - input: receipt.input, - nonce: bigIntToHex(tx.nonce), - transactionIndex: this.TX_INDEX, - value: bigIntToHex(tx.value), - to: receipt.to ? receipt.to : null - } + return { + blockHash: '0x' + block.hash().toString('hex'), + blockNumber: bigIntToHex(block.header.number), + from: receipt.from, + gas: toHex(receipt.gas), + chainId: '0xd05', + gasPrice: '0x4a817c800', // 20000000000 + hash: receipt.transactionHash, + input: receipt.input, + nonce: bigIntToHex(tx.nonce), + transactionIndex: this.TX_INDEX, + value: bigIntToHex(tx.value), + to: receipt.to ? receipt.to : null + } } - }) + }) const b = { baseFeePerGas: '0x01', number: bigIntToHex(block.header.number), diff --git a/libs/remix-simulator/test/events.ts b/libs/remix-simulator/test/events.ts new file mode 100644 index 0000000000..98133679a4 --- /dev/null +++ b/libs/remix-simulator/test/events.ts @@ -0,0 +1,122 @@ +/* global describe, before, it */ +import Web3 from 'web3' +import { Provider } from '../src/index' +const web3 = new Web3() +import * as assert from 'assert' + +describe('Events', () => { + before(async function () { + const provider = new Provider() + await provider.init() + web3.setProvider(provider as any) + }) + + describe('eth_getLogs', () => { + it('should deploy 2 contracts which emit events and retrieve these events using different block ranges', async function () { + const accounts: string[] = await web3.eth.getAccounts() + // deploy the contract "test". + const receiptTest = await web3.eth.sendTransaction({ + from: accounts[0], + gas: 1000000, + data: '0x608060405234801561001057600080fd5b506101ea806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80632801617e14610030575b600080fd5b61004a6004803603810190610045919061015d565b61004c565b005b8073ffffffffffffffffffffffffffffffffffffffff1663a6f9dae1306040518263ffffffff1660e01b81526004016100859190610199565b600060405180830381600087803b15801561009f57600080fd5b505af11580156100b3573d6000803e3d6000fd5b50505050607b7fdcd9c7fa0342f01013bd0bf2bec103a81936162dcebd1f0c38b1d4164c17e0fc60405160405180910390a250565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610118826100ed565b9050919050565b600061012a8261010d565b9050919050565b61013a8161011f565b811461014557600080fd5b50565b60008135905061015781610131565b92915050565b600060208284031215610173576101726100e8565b5b600061018184828501610148565b91505092915050565b6101938161010d565b82525050565b60006020820190506101ae600083018461018a565b9291505056fea2646970667358221220cf5368dd204d44a75752e8ba7512b73d2f54b09f6ca6147e376dd3cf2942b96464736f6c63430008120033' + }) + // deploy the contract "owner", this will trigger an event. + const receiptOwner = await web3.eth.sendTransaction({ + from: accounts[0], + gas: 1000000, + data: '0x608060405234801561001057600080fd5b5061005a6040518060400160405280601b81526020017f4f776e657220636f6e7472616374206465706c6f7965642062793a00000000008152503361011a60201b61015b1760201c565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a361034d565b6101b882826040516024016101309291906102ee565b6040516020818303038152906040527f319af333000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506101bc60201b60201c565b5050565b6101dd816101d86101e060201b6101f71761020160201b60201c565b60201c565b50565b60006a636f6e736f6c652e6c6f679050600080835160208501845afa505050565b61021360201b61023d17819050919050565b61021b61031e565b565b600081519050919050565b600082825260208201905092915050565b60005b8381101561025757808201518184015260208101905061023c565b60008484015250505050565b6000601f19601f8301169050919050565b600061027f8261021d565b6102898185610228565b9350610299818560208601610239565b6102a281610263565b840191505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d8826102ad565b9050919050565b6102e8816102cd565b82525050565b600060408201905081810360008301526103088185610274565b905061031760208301846102df565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052605160045260246000fd5b6104268061035c6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063893d20e81461003b578063a6f9dae114610059575b600080fd5b610043610075565b6040516100509190610288565b60405180910390f35b610073600480360381019061006e91906102d4565b61009e565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b8073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6101f38282604051602401610171929190610391565b6040516020818303038152906040527f319af333000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050610218565b5050565b60006a636f6e736f6c652e6c6f679050600080835160208501845afa505050565b61022f816102276101f7610232565b63ffffffff16565b50565b61023d819050919050565b6102456103c1565b565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061027282610247565b9050919050565b61028281610267565b82525050565b600060208201905061029d6000830184610279565b92915050565b600080fd5b6102b181610267565b81146102bc57600080fd5b50565b6000813590506102ce816102a8565b92915050565b6000602082840312156102ea576102e96102a3565b5b60006102f8848285016102bf565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561033b578082015181840152602081019050610320565b60008484015250505050565b6000601f19601f8301169050919050565b600061036382610301565b61036d818561030c565b935061037d81856020860161031d565b61038681610347565b840191505092915050565b600060408201905081810360008301526103ab8185610358565b90506103ba6020830184610279565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052605160045260246000fdfea2646970667358221220cb7beb012e0831cc632ed85a11a8652f72efc03360c81beb1fcd842a7782c3cb64736f6c63430008120033' + }) + // call function set(Owner p) from "test", this will trigger 2 events, one from each contract. + await web3.eth.sendTransaction({ + from: accounts[0], + to: receiptTest.contractAddress, + gas: 1000000, + data: '0x2801617e' + web3.utils.padLeft(receiptOwner.contractAddress, 64).replace('0x', '') + }) + + const testLogs = await web3.eth.getPastLogs({ + address: receiptTest.contractAddress, + fromBlock: 3, + toBlock: 'latest', + topics: ['0xdcd9c7fa0342f01013bd0bf2bec103a81936162dcebd1f0c38b1d4164c17e0fc', '0x342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a735'] + }) + + let ownerLogs = await web3.eth.getPastLogs({ + address: receiptOwner.contractAddress, + fromBlock: 3, + toBlock: 'latest', + topics: ['0x342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a735', '0xdcd9c7fa0342f01013bd0bf2bec103a81936162dcebd1f0c38b1d4164c17e0fc'] + }) + // this should include the event triggered by the "set" transaction call. + assert.equal(testLogs.length, 1) + assert.equal(ownerLogs.length, 1) + + ownerLogs = await web3.eth.getPastLogs({ + address: receiptOwner.contractAddress, + fromBlock: 2, + toBlock: 'latest', + topics: ['0x342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a735', '0xdcd9c7fa0342f01013bd0bf2bec103a81936162dcebd1f0c38b1d4164c17e0fc'] + }) + // this should include the event triggered from the ctor. + assert.equal(ownerLogs.length, 2) + + ownerLogs = await web3.eth.getPastLogs({ + address: receiptOwner.contractAddress, + fromBlock: 1, + toBlock: 2, + topics: ['0x342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a735', '0xdcd9c7fa0342f01013bd0bf2bec103a81936162dcebd1f0c38b1d4164c17e0fc'] + }) + // this should only include the event triggered from the ctor. + assert.equal(ownerLogs.length, 1) + }) + }) +}) + +/* +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +import "hardhat/console.sol"; + +contract test { + event testEvent(uint indexed value); + function set(Owner p) public { + p.changeOwner(address(this)); + emit testEvent(123); + } +} +contract Owner { + + address private owner; + + // event for EVM logging + event OwnerSet(address indexed oldOwner, address indexed newOwner); + + // modifier to check if caller is owner + modifier isOwner() { + // If the first argument of 'require' evaluates to 'false', execution terminates and all + // changes to the state and to Ether balances are reverted. + // This used to consume all gas in old EVM versions, but not anymore. + // It is often a good idea to use 'require' to check if functions are called correctly. + // As a second argument, you can also provide an explanation about what went wrong. + require(msg.sender == owner, "Caller is not owner"); + _; + } + + constructor() { + console.log("Owner contract deployed by:", msg.sender); + owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor + emit OwnerSet(address(0), owner); + } + + function changeOwner(address newOwner) public { + emit OwnerSet(owner, newOwner); + owner = newOwner; + } + + function getOwner() external view returns (address) { + return owner; + } +} +*/ diff --git a/libs/remix-simulator/test/transactions.ts b/libs/remix-simulator/test/transactions.ts new file mode 100644 index 0000000000..30f9a96fd2 --- /dev/null +++ b/libs/remix-simulator/test/transactions.ts @@ -0,0 +1,40 @@ +/* global describe, before, it */ +import Web3 from 'web3' +import { Provider } from '../src/index' +const web3 = new Web3() +import * as assert from 'assert' + +describe('Transactions', () => { + before(async function () { + const provider = new Provider({ fork: 'shanghai'}) + await provider.init() + web3.setProvider(provider as any) + }) + + describe('eth_sendTransaction', () => { + it('should deploy Storage contract, save a number and retrieve it', async function () { + const accounts: string[] = await web3.eth.getAccounts() + let receipt = await web3.eth.sendTransaction({ + from: accounts[0], + gas: 1000000, + data: '0x608060405234801561000f575f80fd5b506101438061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80632e64cec1146100385780636057361d14610056575b5f80fd5b610040610072565b60405161004d919061009b565b60405180910390f35b610070600480360381019061006b91906100e2565b61007a565b005b5f8054905090565b805f8190555050565b5f819050919050565b61009581610083565b82525050565b5f6020820190506100ae5f83018461008c565b92915050565b5f80fd5b6100c181610083565b81146100cb575f80fd5b50565b5f813590506100dc816100b8565b92915050565b5f602082840312156100f7576100f66100b4565b5b5f610104848285016100ce565b9150509291505056fea2646970667358221220bfa7ddc6d937b635c7a8ad020080923800f04f6b0a685c47330306fd5267626b64736f6c63430008150033' + }) + const storageAddress = receipt.contractAddress + const receiptPull = await web3.eth.getTransactionReceipt(receipt.transactionHash) + assert.equal(receiptPull.contractAddress, receipt.contractAddress) + receipt = await web3.eth.sendTransaction({ + from: accounts[0], + to: storageAddress, + gas: 1000000, + data: '0x6057361d000000000000000000000000000000000000000000000000000000000000000e' + }) + const value = await web3.eth.call({ + from: accounts[0], + to: storageAddress, + data: '0x2e64cec1' + }) + assert.notEqual(value, 15) + assert.equal(value, 14) + }) + }) +}) diff --git a/libs/remix-solidity/package.json b/libs/remix-solidity/package.json index 2f2626acaa..5a9ecbc020 100644 --- a/libs/remix-solidity/package.json +++ b/libs/remix-solidity/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-solidity", - "version": "0.5.15", + "version": "0.5.19", "description": "Tool to load and run Solidity compiler", "main": "src/index.js", "types": "src/index.d.ts", @@ -19,7 +19,7 @@ "@ethereumjs/tx": "^4.1.1", "@ethereumjs/util": "^8.0.5", "@ethereumjs/vm": "^6.4.1", - "@remix-project/remix-lib": "^0.5.36", + "@remix-project/remix-lib": "^0.5.40", "async": "^2.6.2", "eslint-scope": "^5.0.0", "ethers": "^5.4.2", @@ -57,5 +57,5 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme", "typings": "src/index.d.ts", - "gitHead": "bd494e84f12d18787433f25b7dea264c7b2063f8" + "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220" } \ No newline at end of file diff --git a/libs/remix-solidity/src/compiler/compiler-abstract.ts b/libs/remix-solidity/src/compiler/compiler-abstract.ts index 84e2ec3373..52371b1d4f 100644 --- a/libs/remix-solidity/src/compiler/compiler-abstract.ts +++ b/libs/remix-solidity/src/compiler/compiler-abstract.ts @@ -3,53 +3,53 @@ import helper from './helper' import { CompilationResult, CompilerInput, CompilationSourceCode } from './types' export class CompilerAbstract { - languageversion: string - data: CompilationResult - source: CompilationSourceCode - input: CompilerInput - constructor (languageversion: string, data: CompilationResult, source: CompilationSourceCode, input?: CompilerInput) { - this.languageversion = languageversion - this.data = data - this.source = source // source code - this.input = input - } - - getContracts () { - return this.data.contracts || {} - } - - getContract (name) { - return helper.getContract(name, this.data.contracts) - } - - visitContracts (calllback) { - return helper.visitContracts(this.data.contracts, calllback) - } - - getData () { - return this.data - } - - getInput () { - return this.input - } - - 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) { + languageversion: string + data: CompilationResult + source: CompilationSourceCode + input: CompilerInput + constructor (languageversion: string, data: CompilationResult, source: CompilationSourceCode, input?: CompilerInput) { + this.languageversion = languageversion + this.data = data + this.source = source // source code + this.input = input + } + + getContracts () { + return this.data.contracts || {} + } + + getContract (name) { + return helper.getContract(name, this.data.contracts) + } + + visitContracts (calllback) { + return helper.visitContracts(this.data.contracts, calllback) + } + + getData () { + return this.data + } + + getInput () { + return this.input + } + + 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 + const sourcesArray = Object.keys(this.source.sources) + return sourcesArray[0] } + return null + } - getSourceCode () { - return this.source - } + getSourceCode () { + return this.source + } } diff --git a/libs/remix-solidity/src/compiler/compiler.ts b/libs/remix-solidity/src/compiler/compiler.ts index 86e842d779..2e20b0c857 100644 --- a/libs/remix-solidity/src/compiler/compiler.ts +++ b/libs/remix-solidity/src/compiler/compiler.ts @@ -81,12 +81,15 @@ export class Compiler { * @param missingInputs missing import file path list */ - internalCompile(files: Source, missingInputs?: string[]): void { + internalCompile(files: Source, missingInputs?: string[], timeStamp?: number): void { + if(timeStamp != this.state.compilationStartTime && this.state.compilerRetriggerMode == CompilerRetriggerMode.retrigger ) { + return + } this.gatherImports(files, missingInputs, (error, input) => { if (error) { this.state.lastCompilationResult = null this.event.trigger('compilationFinished', [false, { error: { formattedMessage: error, severity: 'error' } }, files, input, this.state.currentVersion]) - } else if (this.state.compileJSON && input) { this.state.compileJSON(input) } + } else if (this.state.compileJSON && input) { this.state.compileJSON(input, timeStamp) } }) } @@ -100,7 +103,7 @@ export class Compiler { this.state.target = target this.state.compilationStartTime = new Date().getTime() this.event.trigger('compilationStarted', []) - this.internalCompile(files) + this.internalCompile(files, null, this.state.compilationStartTime) } /** @@ -157,7 +160,7 @@ export class Compiler { * @param source Source */ - onCompilationFinished(data: CompilationResult, missingInputs?: string[], source?: SourceWithTarget, input?: string, version?: string): void { + onCompilationFinished(data: CompilationResult, missingInputs?: string[], source?: SourceWithTarget, input?: string, version?: string, timeStamp?: number): void { let noFatalErrors = true // ie warnings are ok const checkIfFatalError = (error: CompilationError) => { @@ -173,7 +176,7 @@ export class Compiler { this.event.trigger('compilationFinished', [false, data, source, input, version]) } else if (missingInputs !== undefined && missingInputs.length > 0 && source && source.sources) { // try compiling again with the new set of inputs - this.internalCompile(source.sources, missingInputs) + this.internalCompile(source.sources, missingInputs, timeStamp) } else { data = this.updateInterface(data) if (source) { @@ -292,30 +295,31 @@ export class Compiler { this.state.worker.addEventListener('message', (msg: Record<'data', MessageFromWorker>) => { const data: MessageFromWorker = msg.data if (this.state.compilerRetriggerMode == CompilerRetriggerMode.retrigger && data.timestamp !== this.state.compilationStartTime) { + // drop message from previous compilation return } switch (data.cmd) { - case 'versionLoaded': - if (data.data) this.onCompilerLoaded(data.data, data.license) - break - case 'compiled': - { - let result: CompilationResult - if (data.data && data.job !== undefined && data.job >= 0) { - try { - result = JSON.parse(data.data) - } catch (exception) { - result = { error: { formattedMessage: 'Invalid JSON output from the compiler: ' + exception } } - } - let sources: SourceWithTarget = {} - if (data.job in jobs !== undefined) { - sources = jobs[data.job].sources - delete jobs[data.job] - } - this.onCompilationFinished(result, data.missingInputs, sources, data.input, this.state.currentVersion) - } - break + case 'versionLoaded': + if (data.data) this.onCompilerLoaded(data.data, data.license) + break + case 'compiled': + { + let result: CompilationResult + if (data.data && data.job !== undefined && data.job >= 0) { + try { + result = JSON.parse(data.data) + } catch (exception) { + result = { error: { formattedMessage: 'Invalid JSON output from the compiler: ' + exception } } + } + let sources: SourceWithTarget = {} + if (data.job in jobs !== undefined) { + sources = jobs[data.job].sources + delete jobs[data.job] } + this.onCompilationFinished(result, data.missingInputs, sources, data.input, this.state.currentVersion, data.timestamp) + } + break + } } }) @@ -325,7 +329,7 @@ export class Compiler { this.onCompilationFinished({ error: { formattedMessage } }) }) - this.state.compileJSON = (source: SourceWithTarget) => { + this.state.compileJSON = (source: SourceWithTarget, timeStamp: number) => { if (source && source.sources) { const { optimize, runs, evmVersion, language, useFileConfiguration, configFileContent } = this.state jobs.push({ sources: source }) @@ -342,12 +346,11 @@ export class Compiler { return } - this.state.worker.postMessage({ cmd: 'compile', job: jobs.length - 1, input: input, - timestamp: this.state.compilationStartTime + timestamp: timeStamp }) } } @@ -367,20 +370,6 @@ export class Compiler { gatherImports(files: Source, importHints?: string[], cb?: gatherImportsCallbackInterface): void { importHints = importHints || [] - // FIXME: This will only match imports if the file begins with one '.' - // It should tokenize by lines and check each. - const importRegex = /^\s*import\s*['"]([^'"]+)['"];/g - for (const fileName in files) { - let match: RegExpExecArray | null - while ((match = importRegex.exec(files[fileName].content))) { - let importFilePath = match[1] - if (importFilePath.startsWith('./')) { - const path: RegExpExecArray | null = /(.*\/).*/.exec(fileName) - importFilePath = path ? importFilePath.replace('./', path[1]) : importFilePath.slice(2) - } - if (!importHints.includes(importFilePath)) importHints.push(importFilePath) - } - } while (importHints.length > 0) { const m: string = importHints.pop() as string if (m && m in files) continue diff --git a/libs/remix-solidity/src/compiler/types.ts b/libs/remix-solidity/src/compiler/types.ts index d1001755c0..d86e7b0b74 100644 --- a/libs/remix-solidity/src/compiler/types.ts +++ b/libs/remix-solidity/src/compiler/types.ts @@ -160,7 +160,7 @@ export enum CompilerRetriggerMode { } export interface CompilerState { - compileJSON: ((input: SourceWithTarget) => void) | null, + compileJSON: ((input: SourceWithTarget, timeStamp?: number) => void) | null, worker: any, currentVersion: string| null| undefined, compilerLicense: string| null @@ -502,6 +502,6 @@ export interface BytecodeObject { } } - export interface EsWebWorkerHandlerInterface { +export interface EsWebWorkerHandlerInterface { getWorker(): Worker } diff --git a/libs/remix-solidity/src/lib/es-web-worker/compiler-worker.ts b/libs/remix-solidity/src/lib/es-web-worker/compiler-worker.ts index 96bac07806..60852272fb 100644 --- a/libs/remix-solidity/src/lib/es-web-worker/compiler-worker.ts +++ b/libs/remix-solidity/src/lib/es-web-worker/compiler-worker.ts @@ -6,42 +6,42 @@ const missingInputs: string[] = [] self.onmessage = (e: MessageEvent) => { const data: MessageToWorker = e.data switch (data.cmd) { - case 'loadVersion': - { - (self as any).importScripts(data.data) - const compiler = setupMethods(self) - compileJSON = (input) => { - try { - const missingInputsCallback = (path) => { - missingInputs.push(path) - return { error: 'Deferred import' } - } - return compiler.compile(input, { import: missingInputsCallback }) - } catch (exception) { - return JSON.stringify({ error: 'Uncaught JavaScript exception:\n' + exception }) - } + case 'loadVersion': + { + (self as any).importScripts(data.data) + const compiler = setupMethods(self) + compileJSON = (input) => { + try { + const missingInputsCallback = (path) => { + missingInputs.push(path) + return { error: 'Deferred import' } } - self.postMessage({ - cmd: 'versionLoaded', - data: compiler.version(), - license: compiler.license() - }) - break + return compiler.compile(input, { import: missingInputsCallback }) + } catch (exception) { + return JSON.stringify({ error: 'Uncaught JavaScript exception:\n' + exception }) } + } + self.postMessage({ + cmd: 'versionLoaded', + data: compiler.version(), + license: compiler.license() + }) + break + } - case 'compile': - missingInputs.length = 0 - if (data.input && compileJSON) { - self.postMessage({ - cmd: 'compiled', - job: data.job, - timestamp: data.timestamp, - data: compileJSON(data.input), - input: data.input, - missingInputs: missingInputs - }) - } - break + case 'compile': + missingInputs.length = 0 + if (data.input && compileJSON) { + self.postMessage({ + cmd: 'compiled', + job: data.job, + timestamp: data.timestamp, + data: compileJSON(data.input), + input: data.input, + missingInputs: missingInputs + }) + } + break } } diff --git a/libs/remix-solidity/src/lib/es-web-worker/es-web-worker-handler.ts b/libs/remix-solidity/src/lib/es-web-worker/es-web-worker-handler.ts index 356505c12d..03ba81cb3d 100644 --- a/libs/remix-solidity/src/lib/es-web-worker/es-web-worker-handler.ts +++ b/libs/remix-solidity/src/lib/es-web-worker/es-web-worker-handler.ts @@ -1,12 +1,12 @@ class ESWebWorkerHandler { - constructor() { + constructor() { - } + } - getWorker () { - // @ts-ignore - return new Worker(new URL('./compiler-worker', import.meta.url)) - } + getWorker () { + // @ts-ignore + return new Worker(new URL('./compiler-worker', import.meta.url)) + } } export default ESWebWorkerHandler \ No newline at end of file diff --git a/libs/remix-tests/package.json b/libs/remix-tests/package.json index 383884f119..a9462d0075 100644 --- a/libs/remix-tests/package.json +++ b/libs/remix-tests/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-tests", - "version": "0.2.29", + "version": "0.2.33", "description": "Tool to test Solidity smart contracts", "main": "src/index.js", "types": "./src/index.d.ts", @@ -41,9 +41,9 @@ "@ethereumjs/tx": "^4.1.1", "@ethereumjs/util": "^8.0.5", "@ethereumjs/vm": "^6.4.1", - "@remix-project/remix-lib": "^0.5.36", - "@remix-project/remix-simulator": "^0.2.29", - "@remix-project/remix-solidity": "^0.5.15", + "@remix-project/remix-lib": "^0.5.40", + "@remix-project/remix-simulator": "^0.2.33", + "@remix-project/remix-solidity": "^0.5.19", "@remix-project/remix-url-resolver": "^0.0.42", "ansi-gray": "^0.1.1", "async": "^2.6.0", @@ -78,5 +78,5 @@ "typescript": "^3.3.1" }, "typings": "src/index.d.ts", - "gitHead": "bd494e84f12d18787433f25b7dea264c7b2063f8" + "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220" } \ No newline at end of file diff --git a/libs/remix-tests/src/logger.ts b/libs/remix-tests/src/logger.ts index c82b2b4d4e..e084ed00a2 100644 --- a/libs/remix-tests/src/logger.ts +++ b/libs/remix-tests/src/logger.ts @@ -31,28 +31,28 @@ const logFmt = winston.format.printf((info) => { }) class Log { - logger: Logger; - constructor () { - this.logger = winston.createLogger({ - level: 'info', - transports: [new winston.transports.Console()], - format: winston.format.combine( - winston.format.colorize({ all: true }), - logFmt - ) - }) - } - - setVerbosity (v: LoggerOptions['level']): void { - this.logger.configure({ - level: v, - transports: [new winston.transports.Console()], - format: winston.format.combine( - winston.format.colorize({ all: true }), - logFmt - ) - }) - } + logger: Logger; + constructor () { + this.logger = winston.createLogger({ + level: 'info', + transports: [new winston.transports.Console()], + format: winston.format.combine( + winston.format.colorize({ all: true }), + logFmt + ) + }) + } + + setVerbosity (v: LoggerOptions['level']): void { + this.logger.configure({ + level: v, + transports: [new winston.transports.Console()], + format: winston.format.combine( + winston.format.colorize({ all: true }), + logFmt + ) + }) + } } export default Log diff --git a/libs/remix-tests/tests/testRunner.cli.spec.ts b/libs/remix-tests/tests/testRunner.cli.spec.ts index c4824c9b8b..8ac5505f10 100644 --- a/libs/remix-tests/tests/testRunner.cli.spec.ts +++ b/libs/remix-tests/tests/testRunner.cli.spec.ts @@ -3,35 +3,35 @@ import { resolve } from 'path' import { expect } from 'chai'; describe('testRunner: remix-tests CLI', function(){ - this.timeout(120000) - // remix-tests binary, after build, is used as executable + this.timeout(120000) + // remix-tests binary, after build, is used as executable - const executablePath = resolve(__dirname + '/../../../dist/libs/remix-tests/bin/remix-tests') + const executablePath = resolve(__dirname + '/../../../dist/libs/remix-tests/bin/remix-tests') - const result = spawnSync('ls', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) - if(result) { - const dirContent = result.stdout.toString() - // Install dependencies if 'node_modules' is not already present - if(!dirContent.includes('node_modules')) { - execSync('yarn add @remix-project/remix-lib ../../libs/remix-lib', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) - execSync('yarn add @remix-project/remix-url-resolver ../../libs/remix-url-resolver', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) - execSync('yarn add @remix-project/remix-solidity ../../libs/remix-solidity', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) - execSync('yarn add @remix-project/remix-simulator ../../libs/remix-simulator', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) - execSync('yarn install', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) - } + const result = spawnSync('ls', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) + if(result) { + const dirContent = result.stdout.toString() + // Install dependencies if 'node_modules' is not already present + if(!dirContent.includes('node_modules')) { + execSync('yarn add @remix-project/remix-lib ../../libs/remix-lib', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) + execSync('yarn add @remix-project/remix-url-resolver ../../libs/remix-url-resolver', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) + execSync('yarn add @remix-project/remix-solidity ../../libs/remix-solidity', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) + execSync('yarn add @remix-project/remix-simulator ../../libs/remix-simulator', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) + execSync('yarn install', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) } + } - describe('test various CLI options', function() { - it('remix-tests version', () => { - const res = spawnSync(executablePath, ['-V']) - // eslint-disable-next-line @typescript-eslint/no-var-requires - expect(res.stdout.toString().trim()).to.equal(require('../package.json').version) - }) + describe('test various CLI options', function() { + it('remix-tests version', () => { + const res = spawnSync(executablePath, ['-V']) + // eslint-disable-next-line @typescript-eslint/no-var-requires + expect(res.stdout.toString().trim()).to.equal(require('../package.json').version) + }) - it('remix-tests help', () => { - const res = spawnSync(executablePath, ['-h']) - const expectedHelp = `Usage: remix-tests [options] [command] + it('remix-tests help', () => { + const res = spawnSync(executablePath, ['-h']) + const expectedHelp = `Usage: remix-tests [options] [command] Arguments: file_path path to test file or directory @@ -55,8 +55,8 @@ Options: Commands: version output the version number help output usage information` - expect(res.stdout.toString().trim()).to.equal(expectedHelp) - }) + expect(res.stdout.toString().trim()).to.equal(expectedHelp) + }) it('remix-tests running a test file', function() { const res = spawnSync(executablePath, [resolve(__dirname + '/examples_0/assert_ok_test.sol')]) diff --git a/libs/remix-tests/tests/testRunner.spec.ts b/libs/remix-tests/tests/testRunner.spec.ts index 56ef68cd8a..cbdc1c4aa1 100644 --- a/libs/remix-tests/tests/testRunner.spec.ts +++ b/libs/remix-tests/tests/testRunner.spec.ts @@ -14,476 +14,476 @@ import { ResultsInterface, TestCbInterface, ResultCbInterface } from '../src/ind // In this specific test, we'll use this helper to exclude `time` keys. // Assertions for the existance of these will be made at the correct places. function deepEqualExcluding(a: any, b: any, excludedKeys: string[]) { - function removeKeysFromObject(obj: any, excludedKeys: string[]) { - if (obj !== Object(obj)) { - return obj - } - - if (Object.prototype.toString.call(obj) !== '[object Array]') { - obj = Object.assign({}, obj) - for (const key of excludedKeys) { - delete obj[key] - } + function removeKeysFromObject(obj: any, excludedKeys: string[]) { + if (obj !== Object(obj)) { + return obj + } - return obj - } + if (Object.prototype.toString.call(obj) !== '[object Array]') { + obj = Object.assign({}, obj) + for (const key of excludedKeys) { + delete obj[key] + } - const newObj = [] - for (const idx in obj) { - newObj[idx] = removeKeysFromObject(obj[idx], excludedKeys); - } + return obj + } - return newObj + const newObj = [] + for (const idx in obj) { + newObj[idx] = removeKeysFromObject(obj[idx], excludedKeys); } - const aStripped: any = removeKeysFromObject(a, excludedKeys); - const bStripped: any = removeKeysFromObject(b, excludedKeys); - assert.deepEqual(aStripped, bStripped) + return newObj + } + + const aStripped: any = removeKeysFromObject(a, excludedKeys); + const bStripped: any = removeKeysFromObject(b, excludedKeys); + assert.deepEqual(aStripped, bStripped) } let accounts: string[] const provider: any = new Provider() async function compileAndDeploy(filename: string, callback: any) { - const web3: Web3 = new Web3() - const sourceASTs: any = {} - await provider.init() - web3.setProvider(provider) - extend(web3) - let compilationData: any - async.waterfall([ - function getAccountList(next: any): void { - web3.eth.getAccounts((_err: Error | null | undefined, _accounts: string[]) => { - accounts = _accounts - web3.eth.defaultAccount = accounts[0] - next(_err) - }) - }, - function compile(next: any): void { - compileFileOrFiles(filename, false, { accounts }, null, next) - }, - function deployAllContracts(compilationResult: compilationInterface, asts, next: any): void { - for (const filename in asts) { - if (filename.endsWith('_test.sol')) - sourceASTs[filename] = asts[filename].ast - } - // eslint-disable-next-line no-useless-catch - try { - compilationData = compilationResult - deployAll(compilationResult, web3, accounts, false, null, next) - } catch (e) { - throw e - } - } - ], function (_err: Error | null | undefined, contracts: any): void { - callback(null, compilationData, contracts, sourceASTs, accounts, web3) - }) + const web3: Web3 = new Web3() + const sourceASTs: any = {} + await provider.init() + web3.setProvider(provider) + extend(web3) + let compilationData: any + async.waterfall([ + function getAccountList(next: any): void { + web3.eth.getAccounts((_err: Error | null | undefined, _accounts: string[]) => { + accounts = _accounts + web3.eth.defaultAccount = accounts[0] + next(_err) + }) + }, + function compile(next: any): void { + compileFileOrFiles(filename, false, { accounts }, null, next) + }, + function deployAllContracts(compilationResult: compilationInterface, asts, next: any): void { + for (const filename in asts) { + if (filename.endsWith('_test.sol')) + sourceASTs[filename] = asts[filename].ast + } + // eslint-disable-next-line no-useless-catch + try { + compilationData = compilationResult + deployAll(compilationResult, web3, accounts, false, null, next) + } catch (e) { + throw e + } + } + ], function (_err: Error | null | undefined, contracts: any): void { + callback(null, compilationData, contracts, sourceASTs, accounts, web3) + }) } describe('testRunner', function () { - let tests: any[] = [], results: ResultsInterface; + let tests: any[] = [], results: ResultsInterface; - const testCallback: TestCbInterface = (err, test) => { - if (err) { throw err } + const testCallback: TestCbInterface = (err, test) => { + if (err) { throw err } - if (test.type === 'testPass' || test.type === 'testFailure') { - assert.ok(test.time, 'test time not reported') - assert.ok(!Number.isInteger(test.time || 0), 'test time should not be an integer') - } - - tests.push(test) + if (test.type === 'testPass' || test.type === 'testFailure') { + assert.ok(test.time, 'test time not reported') + assert.ok(!Number.isInteger(test.time || 0), 'test time should not be an integer') } - const resultsCallback = (done) => { - return (err, _results) => { - if (err) { throw err } - results = _results - done() - } + tests.push(test) + } + + const resultsCallback = (done) => { + return (err, _results) => { + if (err) { throw err } + results = _results + done() } + } - describe('#runTest', function () { - this.timeout(10000) - describe('assert library OK method tests', () => { - const filename: string = __dirname + '/examples_0/assert_ok_test.sol' - - before((done) => { - compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { - runTest('AssertOkTest', contracts.AssertOkTest, compilationData[filename]['AssertOkTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) - }) - }) - - after(() => { tests = [] }) - - it('should have 1 passing test', () => { - assert.equal(results.passingNum, 1) - }) - - it('should have 1 failing test', () => { - assert.equal(results.failureNum, 1) - }) - - const hhLogs1 = [["AssertOkTest", "okPassTest"]] - const hhLogs2 = [["AssertOkTest", "okFailTest"]] - it('should return', () => { - deepEqualExcluding(tests, [ - { type: 'accountList', value: accounts }, - { type: 'contract', value: 'AssertOkTest', filename: __dirname + '/examples_0/assert_ok_test.sol' }, - { type: 'testPass', debugTxHash: '0x5b665752a4faf83229259b9b2811d3295be0af633b0051d4b90042283ef55707', value: 'Ok pass test', filename: __dirname + '/examples_0/assert_ok_test.sol', context: 'AssertOkTest', hhLogs: hhLogs1 }, - { type: 'testFailure', debugTxHash: '0xa0a30ad042a7fc3495f72be7ba788d705888ffbbec7173f60bb27e07721510f2', value: 'Ok fail test', filename: __dirname + '/examples_0/assert_ok_test.sol', errMsg: 'okFailTest fails', context: 'AssertOkTest', hhLogs: hhLogs2, assertMethod: 'ok', location: '366:36:0', expected: 'true', returned: 'false' }, - - ], ['time', 'web3']) - }) - }) + describe('#runTest', function () { + this.timeout(10000) + describe('assert library OK method tests', () => { + const filename: string = __dirname + '/examples_0/assert_ok_test.sol' - describe('assert library EQUAL method tests', function () { - const filename: string = __dirname + '/examples_0/assert_equal_test.sol' - - before((done) => { - compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { - runTest('AssertEqualTest', contracts.AssertEqualTest, compilationData[filename]['AssertEqualTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) - }) - }) - - after(() => { tests = [] }) - - it('should have 6 passing test', () => { - assert.equal(results.passingNum, 6) - }) - - it('should have 6 failing test', () => { - assert.equal(results.failureNum, 6) - }) - - it('should return', () => { - deepEqualExcluding(tests, [ - { type: 'accountList', value: accounts }, - { type: 'contract', value: 'AssertEqualTest', filename: __dirname + '/examples_0/assert_equal_test.sol' }, - { type: 'testPass', debugTxHash: '0x233b8d91f0fa068b1a4deae1141178bc3eb79c3d2a6786160595a358363a157c', value: 'Equal uint pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, - { type: 'testFailure', debugTxHash: '0xa5e39c78663c2e5071c08467047ba5b2650d16081b50369700d46d7f90c4d94b', value: 'Equal uint fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalUintFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '273:57:0', expected: '2', returned: '1' }, - { type: 'testPass', debugTxHash: '0x57af51c2c19db390a4ccf72fa3d32347fb3d998e70820909c7876bd8ccebf8a3', value: 'Equal int pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, - { type: 'testFailure', debugTxHash: '0x710f3a54a561c009fcf0277273b8fe337b2c493e9e83e0ae02786d487339ca7b', value: 'Equal int fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalIntFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '493:45:0', expected: '2', returned: '-1' }, - { type: 'testPass', debugTxHash: '0x10c1ed8651110ad5de6adcad8e1284aa5c1fd3a998a1e863bbecc0ec855fcd7b', value: 'Equal bool pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, - { type: 'testFailure', debugTxHash: '0x004871a82968f43e02278eab9dd3d7eb0bbe88b64d459efa50065e5996fe5fad', value: 'Equal bool fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalBoolFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '708:52:0', expected: false, returned: true }, - { type: 'testPass', debugTxHash: '0x64a4d4853ab7907712912cf2120ac2bfd2e08b4767b375250f0e907757546454', value: 'Equal address pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, - { type: 'testFailure', debugTxHash: '0xcf62fb76e3b2eb95d92aa2671a9e81e30fefb944f55e2fb8b97096c45fc74a38', value: 'Equal address fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalAddressFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1015:130:0', expected: '0x1c6637567229159d1eFD45f95A6675e77727E013', returned: '0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9' }, - { type: 'testPass', debugTxHash: '0x18ef613acc128a21282e09cf920b32ef3be648bb35c0299471ddbbbeeb0faf8c', value: 'Equal bytes32 pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, - { type: 'testFailure', debugTxHash: '0x86fbf2f14e13d228f80a87a947841270d8c55073adddf78e8d4e2ba05d724ec6', value: 'Equal bytes32 fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalBytes32FailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1670:48:0', expected: '0x72656d6978000000000000000000000000000000000000000000000000000000', returned: '0x72656d6979000000000000000000000000000000000000000000000000000000' }, - { type: 'testPass', debugTxHash: '0x80b3465f2504b74359790baa009237ba066685b24afa65a31814f1ad1bc4f99f', value: 'Equal string pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, - { type: 'testFailure', debugTxHash: '0x88b035a85c5f87f54a805334817f3e4599b4190d98f25947fe14d7804facd8b7', value: 'Equal string fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalStringFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1916:81:0', expected: 'remix-tests', returned: 'remix' } - ], ['time', 'web3']) - }) + before((done) => { + compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { + runTest('AssertOkTest', contracts.AssertOkTest, compilationData[filename]['AssertOkTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) + }) + + after(() => { tests = [] }) + + it('should have 1 passing test', () => { + assert.equal(results.passingNum, 1) + }) + it('should have 1 failing test', () => { + assert.equal(results.failureNum, 1) + }) + const hhLogs1 = [["AssertOkTest", "okPassTest"]] + const hhLogs2 = [["AssertOkTest", "okFailTest"]] + it('should return', () => { + deepEqualExcluding(tests, [ + { type: 'accountList', value: accounts }, + { type: 'contract', value: 'AssertOkTest', filename: __dirname + '/examples_0/assert_ok_test.sol' }, + { type: 'testPass', debugTxHash: '0x5b665752a4faf83229259b9b2811d3295be0af633b0051d4b90042283ef55707', value: 'Ok pass test', filename: __dirname + '/examples_0/assert_ok_test.sol', context: 'AssertOkTest', hhLogs: hhLogs1 }, + { type: 'testFailure', debugTxHash: '0xa0a30ad042a7fc3495f72be7ba788d705888ffbbec7173f60bb27e07721510f2', value: 'Ok fail test', filename: __dirname + '/examples_0/assert_ok_test.sol', errMsg: 'okFailTest fails', context: 'AssertOkTest', hhLogs: hhLogs2, assertMethod: 'ok', location: '366:36:0', expected: 'true', returned: 'false' }, - describe('assert library NOTEQUAL method tests', function () { - const filename: string = __dirname + '/examples_0/assert_notEqual_test.sol' - - before((done) => { - compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { - runTest('AssertNotEqualTest', contracts.AssertNotEqualTest, compilationData[filename]['AssertNotEqualTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) - }) - }) - - after(() => { tests = [] }) - - it('should have 6 passing test', () => { - assert.equal(results.passingNum, 6) - }) - - it('should have 6 failing test', () => { - assert.equal(results.failureNum, 6) - }) - - it('should return', () => { - deepEqualExcluding(tests, [ - { type: 'accountList', value: accounts }, - { type: 'contract', value: 'AssertNotEqualTest', filename: __dirname + '/examples_0/assert_notEqual_test.sol' }, - { type: 'testPass', debugTxHash: '0xdef34ec7fbc6a3e6c6ef619b424bf8ebf16db16ed3f74500d56d8170d3aeca66', value: 'Not equal uint pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, - { type: 'testFailure', debugTxHash: '0xfcbd35bc5f460e22e885951d560171d687cf90ccdffc41fb5de1beb7075fe4e9', value: 'Not equal uint fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualUintFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '288:63:0', expected: '1', returned: '1' }, - { type: 'testPass', debugTxHash: '0x7f269855c3fc5c677eca416eb85665b8f10df00d3b7ec5dcc00cbf8e6364cba4', value: 'Not equal int pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, - { type: 'testFailure', debugTxHash: '0x76555e218571d4ad69496d7d10ae46d30149c4bfd8c6e15ff2a58668ab6fba62', value: 'Not equal int fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualIntFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '525:52:0', expected: '-2', returned: '-2' }, - { type: 'testPass', debugTxHash: '0x5fe790b3f32b9580c1d5f9a2dbb0e10ddcb62846037d3f5800d47a51bb67cc91', value: 'Not equal bool pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, - { type: 'testFailure', debugTxHash: '0x660d0a73395e6855aea8f6d3450e63640437dc15071842b417c39f40e1d7ae61', value: 'Not equal bool fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualBoolFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '760:57:0', expected: true, returned: true }, - { type: 'testPass', debugTxHash: '0x6fddce5573bd6723acf5a3e4137d698ff78f695873a228939276c4323ddfb132', value: 'Not equal address pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, - // eslint-disable-next-line @typescript-eslint/no-loss-of-precision - { type: 'testFailure', debugTxHash: '0x51479e46db802fb598c61ca0dd630345b9d70cc58667b5a80aa79e8119fa7787', value: 'Not equal address fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualAddressFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '1084:136:0', expected: 0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9, returned: 0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9 }, - { type: 'testPass', debugTxHash: '0xbcaf6d8977b655fdedb280e0e9221d728706d41e85e0973d00c8da1d128022c7', value: 'Not equal bytes32 pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, - { type: 'testFailure', debugTxHash: '0x34008ef0ea908fedbf80471424d801f5069e6e46221f8ee4a2ee16776a6eeef6', value: 'Not equal bytes32 fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualBytes32FailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '1756:54:0', expected: '0x72656d6978000000000000000000000000000000000000000000000000000000', returned: '0x72656d6978000000000000000000000000000000000000000000000000000000' }, - { type: 'testPass', debugTxHash: '0x8e0bc9dedea6e088ca7bd82b1e9fab516be5a52f7716a26ccca8197236aae105', value: 'Not equal string pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, - { type: 'testFailure', debugTxHash: '0x13c6d270c3609ef858dd6d0c79433ca0b43e47b485b2e40ffe363f18f2868ea8', value: 'Not equal string fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualStringFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '2026:81:0', expected: 'remix', returned: 'remix' }, - ], ['time', 'web3']) - }) + ], ['time', 'web3']) + }) + }) + + describe('assert library EQUAL method tests', function () { + const filename: string = __dirname + '/examples_0/assert_equal_test.sol' + + before((done) => { + compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { + runTest('AssertEqualTest', contracts.AssertEqualTest, compilationData[filename]['AssertEqualTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) }) + }) + + after(() => { tests = [] }) + + it('should have 6 passing test', () => { + assert.equal(results.passingNum, 6) + }) + + it('should have 6 failing test', () => { + assert.equal(results.failureNum, 6) + }) + + it('should return', () => { + deepEqualExcluding(tests, [ + { type: 'accountList', value: accounts }, + { type: 'contract', value: 'AssertEqualTest', filename: __dirname + '/examples_0/assert_equal_test.sol' }, + { type: 'testPass', debugTxHash: '0x233b8d91f0fa068b1a4deae1141178bc3eb79c3d2a6786160595a358363a157c', value: 'Equal uint pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, + { type: 'testFailure', debugTxHash: '0xa5e39c78663c2e5071c08467047ba5b2650d16081b50369700d46d7f90c4d94b', value: 'Equal uint fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalUintFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '273:57:0', expected: '2', returned: '1' }, + { type: 'testPass', debugTxHash: '0x57af51c2c19db390a4ccf72fa3d32347fb3d998e70820909c7876bd8ccebf8a3', value: 'Equal int pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, + { type: 'testFailure', debugTxHash: '0x710f3a54a561c009fcf0277273b8fe337b2c493e9e83e0ae02786d487339ca7b', value: 'Equal int fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalIntFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '493:45:0', expected: '2', returned: '-1' }, + { type: 'testPass', debugTxHash: '0x10c1ed8651110ad5de6adcad8e1284aa5c1fd3a998a1e863bbecc0ec855fcd7b', value: 'Equal bool pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, + { type: 'testFailure', debugTxHash: '0x004871a82968f43e02278eab9dd3d7eb0bbe88b64d459efa50065e5996fe5fad', value: 'Equal bool fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalBoolFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '708:52:0', expected: false, returned: true }, + { type: 'testPass', debugTxHash: '0x64a4d4853ab7907712912cf2120ac2bfd2e08b4767b375250f0e907757546454', value: 'Equal address pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, + { type: 'testFailure', debugTxHash: '0xcf62fb76e3b2eb95d92aa2671a9e81e30fefb944f55e2fb8b97096c45fc74a38', value: 'Equal address fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalAddressFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1015:130:0', expected: '0x1c6637567229159d1eFD45f95A6675e77727E013', returned: '0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9' }, + { type: 'testPass', debugTxHash: '0x18ef613acc128a21282e09cf920b32ef3be648bb35c0299471ddbbbeeb0faf8c', value: 'Equal bytes32 pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, + { type: 'testFailure', debugTxHash: '0x86fbf2f14e13d228f80a87a947841270d8c55073adddf78e8d4e2ba05d724ec6', value: 'Equal bytes32 fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalBytes32FailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1670:48:0', expected: '0x72656d6978000000000000000000000000000000000000000000000000000000', returned: '0x72656d6979000000000000000000000000000000000000000000000000000000' }, + { type: 'testPass', debugTxHash: '0x80b3465f2504b74359790baa009237ba066685b24afa65a31814f1ad1bc4f99f', value: 'Equal string pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, + { type: 'testFailure', debugTxHash: '0x88b035a85c5f87f54a805334817f3e4599b4190d98f25947fe14d7804facd8b7', value: 'Equal string fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalStringFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1916:81:0', expected: 'remix-tests', returned: 'remix' } + ], ['time', 'web3']) + }) + }) + + - describe('assert library GREATERTHAN method tests', function () { - const filename: string = __dirname + '/examples_0/assert_greaterThan_test.sol' - - before((done) => { - compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { - runTest('AssertGreaterThanTest', contracts.AssertGreaterThanTest, compilationData[filename]['AssertGreaterThanTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) - }) - }) - - after(() => { tests = [] }) - - it('should have 4 passing test', () => { - assert.equal(results.passingNum, 4) - }) - - it('should have 4 failing test', () => { - assert.equal(results.failureNum, 4) - }) - it('should return', () => { - deepEqualExcluding(tests, [ - { type: 'accountList', value: accounts }, - { type: 'contract', value: 'AssertGreaterThanTest', filename: __dirname + '/examples_0/assert_greaterThan_test.sol' }, - { type: 'testPass', debugTxHash: '0xdc325916fd93227b76231131e52e67f8913d395098c5ac767032db9bd757a91c', value: 'Greater than uint pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' }, - { type: 'testFailure', debugTxHash: '0xf98eea22bb86f13e0bb4072df22b540289a46b332bdb203a1e488d7e14a1dcd4', value: 'Greater than uint fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanUintFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '303:69:0', expected: '4', returned: '1' }, - { type: 'testPass', debugTxHash: '0xef5ef38329ba6aac2f868d53d803053c52b1895a2c25b704260435c141a63bfc', value: 'Greater than int pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' }, - { type: 'testFailure', debugTxHash: '0x6b9430f3f12c12fb11e5a8d32fef849ab34614e644be20c6b41a25e510453440', value: 'Greater than int fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanIntFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '569:67:0', expected: '1', returned: '-1' }, - { type: 'testPass', debugTxHash: '0x4c6e10815a5e82bf2c60950606dc886317f680028a9229ba2dda17b5ea36325a', value: 'Greater than uint int pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' }, - { type: 'testFailure', debugTxHash: '0x989c405c32c8e270a5dea69e6250a514c05dacd6fcf018365a241abc28c2497b', value: 'Greater than uint int fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanUintIntFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '845:71:0', expected: '2', returned: '1' }, - { type: 'testPass', debugTxHash: '0x9fed670ae2061929f71780835b7ea3eb7da6d4fb553cd2d5f62950c353165861', value: 'Greater than int uint pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' }, - { type: 'testFailure', debugTxHash: '0xcf394fd279293cdcf58efc42f3a443595fdb171769a45df01b0c84cd76b3a9a2', value: 'Greater than int uint fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanIntUintFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '1125:76:0', expected: '115792089237316195423570985008687907853269984665640564039457584007913129639836', returned: '100' } - ], ['time', 'web3']) - }) + describe('assert library NOTEQUAL method tests', function () { + const filename: string = __dirname + '/examples_0/assert_notEqual_test.sol' + + before((done) => { + compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { + runTest('AssertNotEqualTest', contracts.AssertNotEqualTest, compilationData[filename]['AssertNotEqualTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) }) + }) + + after(() => { tests = [] }) + + it('should have 6 passing test', () => { + assert.equal(results.passingNum, 6) + }) + + it('should have 6 failing test', () => { + assert.equal(results.failureNum, 6) + }) + + it('should return', () => { + deepEqualExcluding(tests, [ + { type: 'accountList', value: accounts }, + { type: 'contract', value: 'AssertNotEqualTest', filename: __dirname + '/examples_0/assert_notEqual_test.sol' }, + { type: 'testPass', debugTxHash: '0xdef34ec7fbc6a3e6c6ef619b424bf8ebf16db16ed3f74500d56d8170d3aeca66', value: 'Not equal uint pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, + { type: 'testFailure', debugTxHash: '0xfcbd35bc5f460e22e885951d560171d687cf90ccdffc41fb5de1beb7075fe4e9', value: 'Not equal uint fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualUintFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '288:63:0', expected: '1', returned: '1' }, + { type: 'testPass', debugTxHash: '0x7f269855c3fc5c677eca416eb85665b8f10df00d3b7ec5dcc00cbf8e6364cba4', value: 'Not equal int pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, + { type: 'testFailure', debugTxHash: '0x76555e218571d4ad69496d7d10ae46d30149c4bfd8c6e15ff2a58668ab6fba62', value: 'Not equal int fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualIntFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '525:52:0', expected: '-2', returned: '-2' }, + { type: 'testPass', debugTxHash: '0x5fe790b3f32b9580c1d5f9a2dbb0e10ddcb62846037d3f5800d47a51bb67cc91', value: 'Not equal bool pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, + { type: 'testFailure', debugTxHash: '0x660d0a73395e6855aea8f6d3450e63640437dc15071842b417c39f40e1d7ae61', value: 'Not equal bool fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualBoolFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '760:57:0', expected: true, returned: true }, + { type: 'testPass', debugTxHash: '0x6fddce5573bd6723acf5a3e4137d698ff78f695873a228939276c4323ddfb132', value: 'Not equal address pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, + // eslint-disable-next-line @typescript-eslint/no-loss-of-precision + { type: 'testFailure', debugTxHash: '0x51479e46db802fb598c61ca0dd630345b9d70cc58667b5a80aa79e8119fa7787', value: 'Not equal address fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualAddressFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '1084:136:0', expected: 0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9, returned: 0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9 }, + { type: 'testPass', debugTxHash: '0xbcaf6d8977b655fdedb280e0e9221d728706d41e85e0973d00c8da1d128022c7', value: 'Not equal bytes32 pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, + { type: 'testFailure', debugTxHash: '0x34008ef0ea908fedbf80471424d801f5069e6e46221f8ee4a2ee16776a6eeef6', value: 'Not equal bytes32 fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualBytes32FailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '1756:54:0', expected: '0x72656d6978000000000000000000000000000000000000000000000000000000', returned: '0x72656d6978000000000000000000000000000000000000000000000000000000' }, + { type: 'testPass', debugTxHash: '0x8e0bc9dedea6e088ca7bd82b1e9fab516be5a52f7716a26ccca8197236aae105', value: 'Not equal string pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, + { type: 'testFailure', debugTxHash: '0x13c6d270c3609ef858dd6d0c79433ca0b43e47b485b2e40ffe363f18f2868ea8', value: 'Not equal string fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualStringFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '2026:81:0', expected: 'remix', returned: 'remix' }, + ], ['time', 'web3']) + }) + }) - describe('assert library LESSERTHAN method tests', function () { - const filename: string = __dirname + '/examples_0/assert_lesserThan_test.sol' - - before((done) => { - compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { - runTest('AssertLesserThanTest', contracts.AssertLesserThanTest, compilationData[filename]['AssertLesserThanTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) - }) - }) - - after(() => { tests = [] }) - - it('should have 4 passing test', () => { - assert.equal(results.passingNum, 4) - }) - - it('should have 4 failing test', () => { - assert.equal(results.failureNum, 4) - }) - - it('should return', () => { - deepEqualExcluding(tests, [ - { type: 'accountList', value: accounts }, - { type: 'contract', value: 'AssertLesserThanTest', filename: __dirname + '/examples_0/assert_lesserThan_test.sol' }, - { type: 'testPass', debugTxHash: '0x524fb46aa0e8a78bc11a99432908d422450c2933d837f858aeacba9b84706d5c', value: 'Lesser than uint pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' }, - { type: 'testFailure', debugTxHash: '0x0551a67b10b9e13182e8bdb4e530ed92466d5054ae959f999f2c558da2c39d22', value: 'Lesser than uint fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanUintFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '298:67:0', expected: '2', returned: '4' }, - { type: 'testPass', debugTxHash: '0x6d63958d8c3230e837d0ca8335e57262c6e0c6b2c07a5b481842b9ad7329ac28', value: 'Lesser than int pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' }, - { type: 'testFailure', debugTxHash: '0x38e96ef44f4e785db4d40a95862a9797e8cef6de0ce1d059da72ff42e2f3ca62', value: 'Lesser than int fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanIntFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '557:65:0', expected: '-1', returned: '1' }, - { type: 'testPass', debugTxHash: '0x699f9fc2bf7a14134e89b94cd9dc1c537b5d4581a1c26a34a0c3343ddede9608', value: 'Lesser than uint int pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' }, - { type: 'testFailure', debugTxHash: '0xce1391dcfbfdc6c611e357e6c1c9f6cd9f257153ee400cb80bd36af6d239c342', value: 'Lesser than uint int fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanUintIntFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '826:71:0', expected: '-1', returned: '115792089237316195423570985008687907853269984665640564039457584007913129639935' }, - { type: 'testPass', debugTxHash: '0x7040e6664c13e6b35ef1daaef93a8cae36a62150d818183892096a98b921800c', value: 'Lesser than int uint pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' }, - { type: 'testFailure', debugTxHash: '0x8c58bb433ea41760dcf11114232407d703e8ebf7d5e9637e2923282eae5caee6', value: 'Lesser than int uint fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanIntUintFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '1105:69:0', expected: '1', returned: '1' }, - ], ['time', 'web3']) - }) + describe('assert library GREATERTHAN method tests', function () { + const filename: string = __dirname + '/examples_0/assert_greaterThan_test.sol' + + before((done) => { + compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { + runTest('AssertGreaterThanTest', contracts.AssertGreaterThanTest, compilationData[filename]['AssertGreaterThanTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) }) + }) + + after(() => { tests = [] }) + + it('should have 4 passing test', () => { + assert.equal(results.passingNum, 4) + }) + + it('should have 4 failing test', () => { + assert.equal(results.failureNum, 4) + }) + it('should return', () => { + deepEqualExcluding(tests, [ + { type: 'accountList', value: accounts }, + { type: 'contract', value: 'AssertGreaterThanTest', filename: __dirname + '/examples_0/assert_greaterThan_test.sol' }, + { type: 'testPass', debugTxHash: '0xdc325916fd93227b76231131e52e67f8913d395098c5ac767032db9bd757a91c', value: 'Greater than uint pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' }, + { type: 'testFailure', debugTxHash: '0xf98eea22bb86f13e0bb4072df22b540289a46b332bdb203a1e488d7e14a1dcd4', value: 'Greater than uint fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanUintFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '303:69:0', expected: '4', returned: '1' }, + { type: 'testPass', debugTxHash: '0xef5ef38329ba6aac2f868d53d803053c52b1895a2c25b704260435c141a63bfc', value: 'Greater than int pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' }, + { type: 'testFailure', debugTxHash: '0x6b9430f3f12c12fb11e5a8d32fef849ab34614e644be20c6b41a25e510453440', value: 'Greater than int fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanIntFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '569:67:0', expected: '1', returned: '-1' }, + { type: 'testPass', debugTxHash: '0x4c6e10815a5e82bf2c60950606dc886317f680028a9229ba2dda17b5ea36325a', value: 'Greater than uint int pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' }, + { type: 'testFailure', debugTxHash: '0x989c405c32c8e270a5dea69e6250a514c05dacd6fcf018365a241abc28c2497b', value: 'Greater than uint int fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanUintIntFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '845:71:0', expected: '2', returned: '1' }, + { type: 'testPass', debugTxHash: '0x9fed670ae2061929f71780835b7ea3eb7da6d4fb553cd2d5f62950c353165861', value: 'Greater than int uint pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' }, + { type: 'testFailure', debugTxHash: '0xcf394fd279293cdcf58efc42f3a443595fdb171769a45df01b0c84cd76b3a9a2', value: 'Greater than int uint fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanIntUintFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '1125:76:0', expected: '115792089237316195423570985008687907853269984665640564039457584007913129639836', returned: '100' } + ], ['time', 'web3']) + }) + }) - describe('test with before', function () { - const filename: string = __dirname + '/examples_1/simple_storage_test.sol' - - before((done) => { - compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { - runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) - }) - }) - - after(() => { tests = [] }) - - it('should have 3 passing test', () => { - assert.equal(results.passingNum, 3) - }) - - it('should have 1 failing test', () => { - assert.equal(results.failureNum, 1) - }) - - it('should return 6 messages', () => { - deepEqualExcluding(tests, [ - { type: 'accountList', value: accounts }, - { type: 'contract', value: 'MyTest', filename: __dirname + '/examples_1/simple_storage_test.sol' }, - { type: 'testPass', debugTxHash: '0xed5b6898331119c6e3d1185b9de65d87ad7329cc629a8f2d43b966cf180a5dc1', value: 'Initial value should be100', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' }, - { type: 'testPass', debugTxHash: '0x79cae5c4f44edfd7ae3490e01c75df5741b107672cef5e69800e4d30d380a721', value: 'Initial value should not be200', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' }, - { type: 'testFailure', debugTxHash: '0x24a20f7643e88f891e469ef495911ab0b75f99e2b09b9b091e688674910d1506', value: 'Should trigger one fail', filename: __dirname + '/examples_1/simple_storage_test.sol', errMsg: 'uint test 1 fails', context: 'MyTest', assertMethod: 'equal', location: '532:51:1', expected: '2', returned: '1' }, - { type: 'testPass', debugTxHash: '0x08b1f60c908b7e6cf2dd24fc166c755f0fe5336aebfb325cae4ce00ea9bbf932', value: 'Should trigger one pass', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' } - ], ['time', 'web3']) - }) + describe('assert library LESSERTHAN method tests', function () { + const filename: string = __dirname + '/examples_0/assert_lesserThan_test.sol' + + before((done) => { + compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { + runTest('AssertLesserThanTest', contracts.AssertLesserThanTest, compilationData[filename]['AssertLesserThanTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) }) + }) + + after(() => { tests = [] }) + + it('should have 4 passing test', () => { + assert.equal(results.passingNum, 4) + }) + + it('should have 4 failing test', () => { + assert.equal(results.failureNum, 4) + }) + + it('should return', () => { + deepEqualExcluding(tests, [ + { type: 'accountList', value: accounts }, + { type: 'contract', value: 'AssertLesserThanTest', filename: __dirname + '/examples_0/assert_lesserThan_test.sol' }, + { type: 'testPass', debugTxHash: '0x524fb46aa0e8a78bc11a99432908d422450c2933d837f858aeacba9b84706d5c', value: 'Lesser than uint pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' }, + { type: 'testFailure', debugTxHash: '0x0551a67b10b9e13182e8bdb4e530ed92466d5054ae959f999f2c558da2c39d22', value: 'Lesser than uint fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanUintFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '298:67:0', expected: '2', returned: '4' }, + { type: 'testPass', debugTxHash: '0x6d63958d8c3230e837d0ca8335e57262c6e0c6b2c07a5b481842b9ad7329ac28', value: 'Lesser than int pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' }, + { type: 'testFailure', debugTxHash: '0x38e96ef44f4e785db4d40a95862a9797e8cef6de0ce1d059da72ff42e2f3ca62', value: 'Lesser than int fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanIntFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '557:65:0', expected: '-1', returned: '1' }, + { type: 'testPass', debugTxHash: '0x699f9fc2bf7a14134e89b94cd9dc1c537b5d4581a1c26a34a0c3343ddede9608', value: 'Lesser than uint int pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' }, + { type: 'testFailure', debugTxHash: '0xce1391dcfbfdc6c611e357e6c1c9f6cd9f257153ee400cb80bd36af6d239c342', value: 'Lesser than uint int fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanUintIntFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '826:71:0', expected: '-1', returned: '115792089237316195423570985008687907853269984665640564039457584007913129639935' }, + { type: 'testPass', debugTxHash: '0x7040e6664c13e6b35ef1daaef93a8cae36a62150d818183892096a98b921800c', value: 'Lesser than int uint pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' }, + { type: 'testFailure', debugTxHash: '0x8c58bb433ea41760dcf11114232407d703e8ebf7d5e9637e2923282eae5caee6', value: 'Lesser than int uint fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanIntUintFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '1105:69:0', expected: '1', returned: '1' }, + ], ['time', 'web3']) + }) + }) + + describe('test with before', function () { + const filename: string = __dirname + '/examples_1/simple_storage_test.sol' - describe('test with beforeEach', function () { - const filename: string = __dirname + '/examples_2/simple_storage_test.sol' - - before(done => { - compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) - }) - }) - - after(() => { tests = [] }) - - it('should have 2 passing tests', () => { - assert.equal(results.passingNum, 2) - }) - - it('should 0 failing tests', () => { - assert.equal(results.failureNum, 0) - }) - - it('should return 4 messages', () => { - deepEqualExcluding(tests, [ - { type: 'accountList', value: accounts }, - { type: 'contract', value: 'MyTest', filename: __dirname + '/examples_2/simple_storage_test.sol' }, - { type: 'testPass', debugTxHash: '0xed5b6898331119c6e3d1185b9de65d87ad7329cc629a8f2d43b966cf180a5dc1', value: 'Initial value should be100', filename: __dirname + '/examples_2/simple_storage_test.sol', context: 'MyTest' }, - { type: 'testPass', debugTxHash: '0x8ed5b4858405b43ad4052f5690b4b711c0f6cdeb67a64f54084417d43bc54308', value: 'Value is set200', filename: __dirname + '/examples_2/simple_storage_test.sol', context: 'MyTest' } - ], ['time', 'web3']) - }) + before((done) => { + compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { + runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) }) + }) + + after(() => { tests = [] }) + + it('should have 3 passing test', () => { + assert.equal(results.passingNum, 3) + }) + + it('should have 1 failing test', () => { + assert.equal(results.failureNum, 1) + }) + + it('should return 6 messages', () => { + deepEqualExcluding(tests, [ + { type: 'accountList', value: accounts }, + { type: 'contract', value: 'MyTest', filename: __dirname + '/examples_1/simple_storage_test.sol' }, + { type: 'testPass', debugTxHash: '0xed5b6898331119c6e3d1185b9de65d87ad7329cc629a8f2d43b966cf180a5dc1', value: 'Initial value should be100', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' }, + { type: 'testPass', debugTxHash: '0x79cae5c4f44edfd7ae3490e01c75df5741b107672cef5e69800e4d30d380a721', value: 'Initial value should not be200', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' }, + { type: 'testFailure', debugTxHash: '0x24a20f7643e88f891e469ef495911ab0b75f99e2b09b9b091e688674910d1506', value: 'Should trigger one fail', filename: __dirname + '/examples_1/simple_storage_test.sol', errMsg: 'uint test 1 fails', context: 'MyTest', assertMethod: 'equal', location: '532:51:1', expected: '2', returned: '1' }, + { type: 'testPass', debugTxHash: '0x08b1f60c908b7e6cf2dd24fc166c755f0fe5336aebfb325cae4ce00ea9bbf932', value: 'Should trigger one pass', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' } + ], ['time', 'web3']) + }) + }) + + describe('test with beforeEach', function () { + const filename: string = __dirname + '/examples_2/simple_storage_test.sol' - // Test string equality - describe('test string equality', function () { - const filename: string = __dirname + '/examples_3/simple_string_test.sol' - - before(done => { - compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('StringTest', contracts.StringTest, compilationData[filename]['StringTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) - }) - }) - - after(() => { tests = [] }) - - it('should 2 passing tests', () => { - assert.equal(results.passingNum, 2) - }) - - it('should return 4 messages', () => { - deepEqualExcluding(tests, [ - { type: 'accountList', value: accounts }, - { type: 'contract', value: 'StringTest', filename: __dirname + '/examples_3/simple_string_test.sol' }, - { type: 'testPass', debugTxHash: '0x3567da76ffbec37e3b43a41987a7ff3e61b41b4c544f35c010d2d4b39568d6d4', value: 'Initial value should be hello world', filename: __dirname + '/examples_3/simple_string_test.sol', context: 'StringTest' }, - { type: 'testPass', debugTxHash: '0x8619b743ccc99be7d5347a064732474b2d1b69844be65b0e7754c6ac1340d275', value: 'Value should not be hello wordl', filename: __dirname + '/examples_3/simple_string_test.sol', context: 'StringTest' } - ], ['time', 'web3']) - }) + before(done => { + compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { + runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) }) + }) + + after(() => { tests = [] }) + + it('should have 2 passing tests', () => { + assert.equal(results.passingNum, 2) + }) + + it('should 0 failing tests', () => { + assert.equal(results.failureNum, 0) + }) + + it('should return 4 messages', () => { + deepEqualExcluding(tests, [ + { type: 'accountList', value: accounts }, + { type: 'contract', value: 'MyTest', filename: __dirname + '/examples_2/simple_storage_test.sol' }, + { type: 'testPass', debugTxHash: '0xed5b6898331119c6e3d1185b9de65d87ad7329cc629a8f2d43b966cf180a5dc1', value: 'Initial value should be100', filename: __dirname + '/examples_2/simple_storage_test.sol', context: 'MyTest' }, + { type: 'testPass', debugTxHash: '0x8ed5b4858405b43ad4052f5690b4b711c0f6cdeb67a64f54084417d43bc54308', value: 'Value is set200', filename: __dirname + '/examples_2/simple_storage_test.sol', context: 'MyTest' } + ], ['time', 'web3']) + }) + }) - // Test multiple directory import in test contract - describe('test multiple directory import in test contract', function () { - const filename: string = __dirname + '/examples_5/test/simple_storage_test.sol' - - before(done => { - compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('StorageResolveTest', contracts.StorageResolveTest, compilationData[filename]['StorageResolveTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) - }) - }) - - after(() => { tests = [] }) - - it('should 3 passing tests', () => { - assert.equal(results.passingNum, 3) - }) - - it('should return 4 messages', () => { - deepEqualExcluding(tests, [ - { type: 'accountList', value: accounts }, - { type: 'contract', value: 'StorageResolveTest', filename: __dirname + '/examples_5/test/simple_storage_test.sol' }, - { type: 'testPass', debugTxHash: '0xed5b6898331119c6e3d1185b9de65d87ad7329cc629a8f2d43b966cf180a5dc1', value: 'Initial value should be100', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' }, - { type: 'testPass', debugTxHash: '0x6893fe4f5a83cc51f03c9237ab93b93ffd826236167d58e20666be4c1b3128a4', value: 'Check if even', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' }, - { type: 'testPass', debugTxHash: '0x64e600b32be681b68926660042ddd96f22d07949b424959811b8acb56e72f719', value: 'Check if odd', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' } - ], ['time', 'web3']) - }) + // Test string equality + describe('test string equality', function () { + const filename: string = __dirname + '/examples_3/simple_string_test.sol' + + before(done => { + compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { + runTest('StringTest', contracts.StringTest, compilationData[filename]['StringTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) }) + }) + + after(() => { tests = [] }) + + it('should 2 passing tests', () => { + assert.equal(results.passingNum, 2) + }) + + it('should return 4 messages', () => { + deepEqualExcluding(tests, [ + { type: 'accountList', value: accounts }, + { type: 'contract', value: 'StringTest', filename: __dirname + '/examples_3/simple_string_test.sol' }, + { type: 'testPass', debugTxHash: '0x3567da76ffbec37e3b43a41987a7ff3e61b41b4c544f35c010d2d4b39568d6d4', value: 'Initial value should be hello world', filename: __dirname + '/examples_3/simple_string_test.sol', context: 'StringTest' }, + { type: 'testPass', debugTxHash: '0x8619b743ccc99be7d5347a064732474b2d1b69844be65b0e7754c6ac1340d275', value: 'Value should not be hello wordl', filename: __dirname + '/examples_3/simple_string_test.sol', context: 'StringTest' } + ], ['time', 'web3']) + }) + }) - //Test SafeMath library methods - describe('test SafeMath library', function () { - const filename: string = __dirname + '/examples_4/SafeMath_test.sol' + // Test multiple directory import in test contract + describe('test multiple directory import in test contract', function () { + const filename: string = __dirname + '/examples_5/test/simple_storage_test.sol' - before(done => { - compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('SafeMathTest', contracts.SafeMathTest, compilationData[filename]['SafeMathTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) - }) - }) + before(done => { + compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { + runTest('StorageResolveTest', contracts.StorageResolveTest, compilationData[filename]['StorageResolveTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + }) + }) + + after(() => { tests = [] }) + + it('should 3 passing tests', () => { + assert.equal(results.passingNum, 3) + }) + + it('should return 4 messages', () => { + deepEqualExcluding(tests, [ + { type: 'accountList', value: accounts }, + { type: 'contract', value: 'StorageResolveTest', filename: __dirname + '/examples_5/test/simple_storage_test.sol' }, + { type: 'testPass', debugTxHash: '0xed5b6898331119c6e3d1185b9de65d87ad7329cc629a8f2d43b966cf180a5dc1', value: 'Initial value should be100', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' }, + { type: 'testPass', debugTxHash: '0x6893fe4f5a83cc51f03c9237ab93b93ffd826236167d58e20666be4c1b3128a4', value: 'Check if even', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' }, + { type: 'testPass', debugTxHash: '0x64e600b32be681b68926660042ddd96f22d07949b424959811b8acb56e72f719', value: 'Check if odd', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' } + ], ['time', 'web3']) + }) + }) - after(() => { tests = [] }) + //Test SafeMath library methods + describe('test SafeMath library', function () { + const filename: string = __dirname + '/examples_4/SafeMath_test.sol' - it('should have 10 passing tests', () => { - assert.equal(results.passingNum, 10) - }) - it('should have 0 failing tests', () => { - assert.equal(results.failureNum, 0) - }) + before(done => { + compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { + runTest('SafeMathTest', contracts.SafeMathTest, compilationData[filename]['SafeMathTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) }) + }) - //Test signed/unsigned integer weight - describe('test number weight', function () { - const filename: string = __dirname + '/number/number_test.sol' + after(() => { tests = [] }) - before(done => { - compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('IntegerTest', contracts.IntegerTest, compilationData[filename]['IntegerTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) - }) - }) + it('should have 10 passing tests', () => { + assert.equal(results.passingNum, 10) + }) + it('should have 0 failing tests', () => { + assert.equal(results.failureNum, 0) + }) + }) - after(() => { tests = [] }) + //Test signed/unsigned integer weight + describe('test number weight', function () { + const filename: string = __dirname + '/number/number_test.sol' - it('should have 6 passing tests', () => { - assert.equal(results.passingNum, 6) - }) - it('should have 2 failing tests', () => { - assert.equal(results.failureNum, 2) - }) + before(done => { + compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { + runTest('IntegerTest', contracts.IntegerTest, compilationData[filename]['IntegerTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) }) + }) - // Test Transaction with custom sender & value - describe('various sender', function () { - const filename: string = __dirname + '/various_sender/sender_and_value_test.sol' + after(() => { tests = [] }) - before(done => { - compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('SenderAndValueTest', contracts.SenderAndValueTest, compilationData[filename]['SenderAndValueTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) - }) - }) + it('should have 6 passing tests', () => { + assert.equal(results.passingNum, 6) + }) + it('should have 2 failing tests', () => { + assert.equal(results.failureNum, 2) + }) + }) - after(() => { tests = [] }) + // Test Transaction with custom sender & value + describe('various sender', function () { + const filename: string = __dirname + '/various_sender/sender_and_value_test.sol' - it('should have 17 passing tests', () => { - assert.equal(results.passingNum, 17) - }) - it('should have 0 failing tests', () => { - assert.equal(results.failureNum, 0) - }) + before(done => { + compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { + runTest('SenderAndValueTest', contracts.SenderAndValueTest, compilationData[filename]['SenderAndValueTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) }) + }) - // Test `runTest` method without sending contract object (should throw error) - describe('runTest method without contract json interface', function () { - const filename: string = __dirname + '/various_sender/sender_and_value_test.sol' - const errorCallback: any = (done) => { - return (err, _results) => { - if (err && err.message.includes('Contract interface not available')) { - results = _results - done() - } - else throw err - } - } - before(done => { - compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('SenderAndValueTest', undefined, compilationData[filename]['SenderAndValueTest'], asts[filename], { accounts }, testCallback, errorCallback(done)) - }) - }) - - it('should have 0 passing tests', () => { - assert.equal(results.passingNum, 0) - }) - it('should have 0 failing tests', () => { - assert.equal(results.failureNum, 0) - }) - }) + after(() => { tests = [] }) + + it('should have 17 passing tests', () => { + assert.equal(results.passingNum, 17) + }) + it('should have 0 failing tests', () => { + assert.equal(results.failureNum, 0) + }) + }) + // Test `runTest` method without sending contract object (should throw error) + describe('runTest method without contract json interface', function () { + const filename: string = __dirname + '/various_sender/sender_and_value_test.sol' + const errorCallback: any = (done) => { + return (err, _results) => { + if (err && err.message.includes('Contract interface not available')) { + results = _results + done() + } + else throw err + } + } + before(done => { + compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { + runTest('SenderAndValueTest', undefined, compilationData[filename]['SenderAndValueTest'], asts[filename], { accounts }, testCallback, errorCallback(done)) + }) + }) + + it('should have 0 passing tests', () => { + assert.equal(results.passingNum, 0) + }) + it('should have 0 failing tests', () => { + assert.equal(results.failureNum, 0) + }) }) + + }) }) \ No newline at end of file diff --git a/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx index d0dc3f0c6d..46b7f851c2 100644 --- a/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx @@ -1,10 +1,10 @@ -import React, { useEffect, useState, useRef } from 'react' +import React, {useEffect, useState, useRef} from 'react' import Draggable from 'react-draggable' import './dragbar.css' interface IRemixDragBarUi { - refObject: React.MutableRefObject; - setHideStatus: (hide: boolean) => void; + refObject: React.MutableRefObject + setHideStatus: (hide: boolean) => void hidden: boolean minWidth: number maximiseTrigger: number @@ -53,19 +53,17 @@ const DragBar = (props: IRemixDragBarUi) => { useEffect(() => { window.addEventListener('resize', handleResize) // TODO: not a good way to wait on the ref doms element to be rendered of course - setTimeout(() => - handleResize(), 2000) + setTimeout(() => handleResize(), 2000) return () => window.removeEventListener('resize', handleResize) }, []) function stopDrag(data: any) { setDragState(false) - console.log("drag") if (data.x < props.minWidth + offset) { setDragBarPosX(offset) props.setHideStatus(true) } else { - props.refObject.current.style.width = (data.x - offset) + 'px' + props.refObject.current.style.width = data.x - offset + 'px' setTimeout(() => { props.setHideStatus(false) setDragBarPosX(offset + props.refObject.current.offsetWidth) @@ -76,12 +74,14 @@ const DragBar = (props: IRemixDragBarUi) => { function startDrag() { setDragState(true) } - return <> -
- -
-
- + return ( + <> +
+ +
+
+ + ) } export default DragBar diff --git a/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogViewPlugin.tsx b/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogViewPlugin.tsx index d5610de56c..091795a900 100644 --- a/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogViewPlugin.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogViewPlugin.tsx @@ -1,13 +1,13 @@ -import React, { useContext, useEffect } from 'react' -import { AppContext } from '../../context/context' -import { useDialogDispatchers } from '../../context/provider' +import React, {useContext, useEffect} from 'react' +import {AppContext} from '../../context/context' +import {useDialogDispatchers} from '../../context/provider' const DialogViewPlugin = () => { - const { modal, alert, toast } = useDialogDispatchers() + const {modal, alert, toast} = useDialogDispatchers() const app = useContext(AppContext) useEffect(() => { - app.modal.setDispatcher({ modal, alert, toast }) + app.modal.setDispatcher({modal, alert, toast}) }, []) return <> } diff --git a/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogs.tsx b/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogs.tsx index 90bd71a05d..052b8661b3 100644 --- a/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogs.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/components/modals/dialogs.tsx @@ -1,16 +1,17 @@ import React from 'react' -import { useDialogDispatchers, useDialogs } from '../../context/provider' -import { Toaster } from '@remix-ui/toaster' +import {useDialogDispatchers, useDialogs} from '../../context/provider' +import {Toaster} from '@remix-ui/toaster' import ModalWrapper from './modal-wrapper' const AppDialogs = () => { - const { handleHideModal, handleToaster } = useDialogDispatchers() - const { focusModal, focusToaster } = useDialogs() + const {handleHideModal, handleToaster} = useDialogDispatchers() + const {focusModal, focusToaster} = useDialogs() return ( <> - ) + + ) } export default AppDialogs diff --git a/libs/remix-ui/app/src/lib/remix-app/components/modals/matomo.tsx b/libs/remix-ui/app/src/lib/remix-app/components/modals/matomo.tsx index 276a3ee47b..86777b5a6c 100644 --- a/libs/remix-ui/app/src/lib/remix-app/components/modals/matomo.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/components/modals/matomo.tsx @@ -1,30 +1,60 @@ -import React, { useContext, useEffect, useState } from 'react' -import { AppContext } from '../../context/context' -import { useDialogDispatchers } from '../../context/provider' +import React, {useContext, useEffect, useState} from 'react' +import {AppContext} from '../../context/context' +import {useDialogDispatchers} from '../../context/provider' declare global { interface Window { _paq: any } } -const _paq = window._paq = window._paq || [] +const _paq = (window._paq = window._paq || []) const MatomoDialog = (props) => { - const { settings, showMatamo, appManager } = useContext(AppContext) - const { modal } = useDialogDispatchers() + const {settings, showMatamo, appManager} = useContext(AppContext) + const {modal} = useDialogDispatchers() const [visible, setVisible] = useState(props.hide) const message = () => { - return (<>

An Opt-in version of Matomo, an open source data analytics platform is being used to improve Remix IDE.

-

We realize that our users have sensitive information in their code and that their privacy - your privacy - must be protected.

-

All data collected through Matomo is stored on our own server - no data is ever given to third parties. Our analytics reports are public: take a look.

-

We do not collect nor store any personally identifiable information (PII).

-

For more info, see: Matomo Analyitcs on Remix iDE.

-

You can change your choice in the Settings panel anytime.

) + return ( + <> +

+ An Opt-in version of{' '} + + Matomo + + , an open source data analytics platform is being used to improve Remix IDE. +

+

We realize that our users have sensitive information in their code and that their privacy - your privacy - must be protected.

+

+ All data collected through Matomo is stored on our own server - no data is ever given to third parties. Our analytics reports are public:{' '} + + take a look + + . +

+

We do not collect nor store any personally identifiable information (PII).

+

+ For more info, see:{' '} + + Matomo Analyitcs on Remix iDE + + . +

+

You can change your choice in the Settings panel anytime.

+ + ) } useEffect(() => { if (visible && showMatamo) { - modal({ id: 'matomoModal', title: 'Help us to improve Remix IDE', message: message(), okLabel: 'Accept', okFn: handleModalOkClick, cancelLabel: 'Decline', cancelFn: declineModal }) + modal({ + id: 'matomoModal', + title: 'Help us to improve Remix IDE', + message: message(), + okLabel: 'Accept', + okFn: handleModalOkClick, + cancelLabel: 'Decline', + cancelFn: declineModal + }) } }, [visible]) @@ -44,7 +74,7 @@ const MatomoDialog = (props) => { setVisible(false) } - return (<>) + return <> } export default MatomoDialog diff --git a/libs/remix-ui/app/src/lib/remix-app/components/modals/modal-wrapper.tsx b/libs/remix-ui/app/src/lib/remix-app/components/modals/modal-wrapper.tsx index 450d59f1de..07b974d3fe 100644 --- a/libs/remix-ui/app/src/lib/remix-app/components/modals/modal-wrapper.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/components/modals/modal-wrapper.tsx @@ -1,6 +1,6 @@ -import React, { useEffect, useRef, useState } from 'react' -import { ModalDialog, ModalDialogProps, ValidationResult } from '@remix-ui/modal-dialog' -import { ModalTypes } from '../../types' +import React, {useEffect, useRef, useState} from 'react' +import {ModalDialog, ModalDialogProps, ValidationResult} from '@remix-ui/modal-dialog' +import {ModalTypes} from '../../types' interface ModalWrapperProps extends ModalDialogProps { modalType?: ModalTypes @@ -28,26 +28,33 @@ const ModalWrapper = (props: ModalWrapperProps) => { if (ref.current === undefined && formRef.current === undefined) { onOkFn() } else if (formRef.current) { - (props.okFn) ? props.okFn(getFormData()) : props.resolve(getFormData()) - } else if(ref.current) { - // @ts-ignore: Object is possibly 'null'. - (props.okFn) ? props.okFn(ref.current.value) : props.resolve(ref.current.value) + props.okFn ? props.okFn(getFormData()) : props.resolve(getFormData()) + } else if (ref.current) { + props.okFn + ? // @ts-ignore: Object is possibly 'null'. + props.okFn(ref.current.value) + : // @ts-ignore: Object is possibly 'null'. + props.resolve(ref.current.value) } } const onOkFn = async () => { - (props.okFn) ? props.okFn(data.current) : props.resolve(data.current || true) + props.okFn ? props.okFn(data.current) : props.resolve(data.current || true) } const onCancelFn = async () => { - (props.cancelFn) ? props.cancelFn() : props.resolve(false) + props.cancelFn ? props.cancelFn() : props.resolve(false) } const onInputChanged = (event) => { if (props.validationFn) { const validation = props.validationFn(event.target.value) - setState(prevState => { - return { ...prevState, message: createModalMessage(props.defaultValue, validation), validation } + setState((prevState) => { + return { + ...prevState, + message: createModalMessage(props.defaultValue, validation), + validation + } }) } } @@ -56,8 +63,15 @@ const ModalWrapper = (props: ModalWrapperProps) => { return ( <> {props.message} - - {validation && !validation.valid && {validation.message}} + + {validation && !validation.valid && {validation.message}} ) } @@ -65,8 +79,8 @@ const ModalWrapper = (props: ModalWrapperProps) => { const onFormChanged = () => { if (props.validationFn) { const validation = props.validationFn(getFormData()) - setState(prevState => { - return { ...prevState, message: createForm(validation), validation } + setState((prevState) => { + return {...prevState, message: createForm(validation), validation} }) } } @@ -74,10 +88,10 @@ const ModalWrapper = (props: ModalWrapperProps) => { const createForm = (validation: ValidationResult) => { return ( <> -
+ {props.message} -
- {validation && !validation.valid && {validation.message}} + + {validation && !validation.valid && {validation.message}} ) } @@ -86,30 +100,30 @@ const ModalWrapper = (props: ModalWrapperProps) => { data.current = props.data if (props.modalType) { switch (props.modalType) { - case ModalTypes.prompt: - case ModalTypes.password: - setState({ - ...props, - okFn: onFinishPrompt, - cancelFn: onCancelFn, - message: createModalMessage(props.defaultValue, { valid: true }) - }) - break - case ModalTypes.form: - setState({ - ...props, - okFn: onFinishPrompt, - cancelFn: onCancelFn, - message: createForm({ valid: true }) - }) - break - default: - setState({ - ...props, - okFn: onOkFn, - cancelFn: onCancelFn - }) - break + case ModalTypes.prompt: + case ModalTypes.password: + setState({ + ...props, + okFn: onFinishPrompt, + cancelFn: onCancelFn, + message: createModalMessage(props.defaultValue, {valid: true}) + }) + break + case ModalTypes.form: + setState({ + ...props, + okFn: onFinishPrompt, + cancelFn: onCancelFn, + message: createForm({valid: true}) + }) + break + default: + setState({ + ...props, + okFn: onOkFn, + cancelFn: onCancelFn + }) + break } } else { setState({ @@ -122,14 +136,12 @@ const ModalWrapper = (props: ModalWrapperProps) => { // reset the message and input if any, so when the modal is shown again it doesn't show the previous value. const handleHide = () => { - setState(prevState => { - return { ...prevState, message: '' } + setState((prevState) => { + return {...prevState, message: ''} }) props.handleHide() } - return ( - - ) + return } export default ModalWrapper diff --git a/libs/remix-ui/app/src/lib/remix-app/components/modals/origin-warning.tsx b/libs/remix-ui/app/src/lib/remix-app/components/modals/origin-warning.tsx index 61d25db2f6..f36e5f0938 100644 --- a/libs/remix-ui/app/src/lib/remix-app/components/modals/origin-warning.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/components/modals/origin-warning.tsx @@ -1,22 +1,26 @@ -import React, { useEffect, useState } from 'react' -import { ModalDialog } from '@remix-ui/modal-dialog' -import { useDialogDispatchers } from '../../context/provider' +import React, {useEffect, useState} from 'react' +import {ModalDialog} from '@remix-ui/modal-dialog' +import {useDialogDispatchers} from '../../context/provider' const OriginWarning = () => { - const { alert } = useDialogDispatchers() + const {alert} = useDialogDispatchers() const [content, setContent] = useState(null) useEffect(() => { // check the origin and warn message if (window.location.hostname === 'yann300.github.io') { setContent('This UNSTABLE ALPHA branch of Remix has been moved to http://ethereum.github.io/remix-live-alpha.') - } else if (window.location.hostname === 'remix-alpha.ethereum.org' || - (window.location.hostname === 'ethereum.github.io' && window.location.pathname.indexOf('/remix-live-alpha') === 0)) { + } else if ( + window.location.hostname === 'remix-alpha.ethereum.org' || + (window.location.hostname === 'ethereum.github.io' && window.location.pathname.indexOf('/remix-live-alpha') === 0) + ) { setContent('Welcome to the Remix alpha instance. Please use it to try out latest features. But use preferably https://remix.ethereum.org for any production work.') - } else if (window.location.protocol.indexOf('http') === 0 && - window.location.hostname !== 'remix.ethereum.org' && - window.location.hostname !== 'localhost' && - window.location.hostname !== '127.0.0.1') { + } else if ( + window.location.protocol.indexOf('http') === 0 && + window.location.hostname !== 'remix.ethereum.org' && + window.location.hostname !== 'localhost' && + window.location.hostname !== '127.0.0.1' + ) { setContent(`The Remix IDE has moved to http://remix.ethereum.org.\n This instance of Remix you are visiting WILL NOT BE UPDATED.\n Please make a backup of your contracts and start using http://remix.ethereum.org`) @@ -25,11 +29,11 @@ const OriginWarning = () => { useEffect(() => { if (content) { - alert({ id: 'warningOriging', title: null, message: content }) + alert({id: 'warningOriging', title: null, message: content}) } }, [content]) - return (<>) + return <> } export default OriginWarning diff --git a/libs/remix-ui/app/src/lib/remix-app/components/splashscreen.tsx b/libs/remix-ui/app/src/lib/remix-app/components/splashscreen.tsx index 44e55a4db4..4f013c4761 100644 --- a/libs/remix-ui/app/src/lib/remix-app/components/splashscreen.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/components/splashscreen.tsx @@ -1,16 +1,19 @@ import React from 'react' const RemixSplashScreen = (props) => { - return (<>
- - - - - -
- REMIX IDE -
-
) + return ( + <> + {' '} +
+ + + + + +
REMIX IDE
+
+ + ) } export default RemixSplashScreen diff --git a/libs/remix-ui/app/src/lib/remix-app/context/context.tsx b/libs/remix-ui/app/src/lib/remix-app/context/context.tsx index ca69771f80..1dae1787f1 100644 --- a/libs/remix-ui/app/src/lib/remix-app/context/context.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/context/context.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { AlertModal, AppModal } from '../interface' -import { ModalInitialState } from '../state/modals' +import {AlertModal, AppModal} from '../interface' +import {ModalInitialState} from '../state/modals' export const AppContext = React.createContext(null) @@ -8,12 +8,12 @@ export interface dispatchModalInterface { modal: (data: AppModal) => void toast: (message: string | JSX.Element) => void alert: (data: AlertModal) => void - handleHideModal: () => void, + handleHideModal: () => void handleToaster: () => void } export const dispatchModalContext = React.createContext({ - modal: (data: AppModal) => { }, + modal: (data: AppModal) => {}, toast: (message: string | JSX.Element) => {}, alert: (data: AlertModal) => {}, handleHideModal: () => {}, diff --git a/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx b/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx index 635500a8b3..c267e50e7c 100644 --- a/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/context/provider.tsx @@ -1,13 +1,13 @@ -import React, { useReducer } from 'react' -import { modalActionTypes } from '../actions/modals' -import { AlertModal, AppModal } from '../interface' -import { modalReducer } from '../reducer/modals' -import { ModalInitialState } from '../state/modals' -import { ModalTypes } from '../types' -import { AppContext, dispatchModalContext, modalContext } from './context' +import React, {useReducer} from 'react' +import {modalActionTypes} from '../actions/modals' +import {AlertModal, AppModal} from '../interface' +import {modalReducer} from '../reducer/modals' +import {ModalInitialState} from '../state/modals' +import {ModalTypes} from '../types' +import {AppContext, dispatchModalContext, modalContext} from './context' -export const ModalProvider = ({ children = [], reducer = modalReducer, initialState = ModalInitialState } = {}) => { - const [{ modals, toasters, focusModal, focusToaster }, dispatch] = useReducer(reducer, initialState) +export const ModalProvider = ({children = [], reducer = modalReducer, initialState = ModalInitialState} = {}) => { + const [{modals, toasters, focusModal, focusToaster}, dispatch] = useReducer(reducer, initialState) const onNextFn = async () => { dispatch({ @@ -16,17 +16,40 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt } const modal = (modalData: AppModal) => { - const { id, title, message, validationFn, okLabel, okFn, cancelLabel, cancelFn, modalType, defaultValue, hideFn, data } = modalData + const {id, title, message, validationFn, okLabel, okFn, cancelLabel, cancelFn, modalType, defaultValue, hideFn, data} = modalData return new Promise((resolve, reject) => { dispatch({ type: modalActionTypes.setModal, - payload: { id, title, message, okLabel, validationFn, okFn, cancelLabel, cancelFn, modalType: modalType || ModalTypes.default, defaultValue: defaultValue, hideFn, resolve, next: onNextFn, data } + payload: { + id, + title, + message, + okLabel, + validationFn, + okFn, + cancelLabel, + cancelFn, + modalType: modalType || ModalTypes.default, + defaultValue: defaultValue, + hideFn, + resolve, + next: onNextFn, + data + } }) }) } const alert = (modalData: AlertModal) => { - return modal({ id: modalData.id, title: modalData.title || 'Alert', message: modalData.message || modalData.title, okLabel: 'OK', okFn: (value?:any) => {}, cancelLabel: '', cancelFn: () => {} }) + return modal({ + id: modalData.id, + title: modalData.title || 'Alert', + message: modalData.message || modalData.title, + okLabel: 'OK', + okFn: (value?: any) => {}, + cancelLabel: '', + cancelFn: () => {} + }) } const handleHideModal = () => { @@ -39,7 +62,7 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt const toast = (message: string | JSX.Element) => { dispatch({ type: modalActionTypes.setToast, - payload: { message, timestamp: Date.now() } + payload: {message, timestamp: Date.now()} }) } @@ -50,17 +73,19 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt }) } - return ( - - {children} - - ) + return ( + + {children} + + ) } -export const AppProvider = ({ children = [], value = {} } = {}) => { - return - {children} - +export const AppProvider = ({children = [], value = {}} = {}) => { + return ( + + {children} + + ) } export const useDialogs = () => { diff --git a/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts b/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts index e2961285d6..4330d967a6 100644 --- a/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts +++ b/libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts @@ -4,80 +4,80 @@ import { AppModal, ModalState } from '../interface' export const modalReducer = (state: ModalState = ModalInitialState, action: ModalAction) => { switch (action.type) { - case modalActionTypes.setModal: { - const timestamp = Date.now() - const focusModal: AppModal = { - timestamp, - id: action.payload.id || timestamp.toString(), - hide: false, - title: action.payload.title, - validationFn: action.payload.validationFn, - message: action.payload.message, - okLabel: action.payload.okLabel, - okFn: action.payload.okFn, - cancelLabel: action.payload.cancelLabel, - cancelFn: action.payload.cancelFn, - modalType: action.payload.modalType, - defaultValue: action.payload.defaultValue, - hideFn: action.payload.hideFn, - resolve: action.payload.resolve, - next: action.payload.next, - data: action.payload.data - } + case modalActionTypes.setModal: { + const timestamp = Date.now() + const focusModal: AppModal = { + timestamp, + id: action.payload.id || timestamp.toString(), + hide: false, + title: action.payload.title, + validationFn: action.payload.validationFn, + message: action.payload.message, + okLabel: action.payload.okLabel, + okFn: action.payload.okFn, + cancelLabel: action.payload.cancelLabel, + cancelFn: action.payload.cancelFn, + modalType: action.payload.modalType, + defaultValue: action.payload.defaultValue, + hideFn: action.payload.hideFn, + resolve: action.payload.resolve, + next: action.payload.next, + data: action.payload.data + } - const modalList: AppModal[] = state.modals.slice() - modalList.push(focusModal) + const modalList: AppModal[] = state.modals.slice() + modalList.push(focusModal) - if (modalList.length === 1) { - return { ...state, modals: modalList, focusModal } - } else { - return { ...state, modals: modalList } - } - } - case modalActionTypes.handleHideModal: { - setTimeout(() => { - if (state.focusModal.hideFn) { - state.focusModal.hideFn() - } - if (state.focusModal.resolve) { - state.focusModal.resolve(undefined) - } - if (state.focusModal.next) { - state.focusModal.next() - } - }, 250) - const modalList: AppModal[] = state.modals.slice() - modalList.shift() // remove the current modal from the list - state.focusModal = { ...state.focusModal, hide: true, message: null } + if (modalList.length === 1) { + return { ...state, modals: modalList, focusModal } + } else { return { ...state, modals: modalList } } - case modalActionTypes.processQueue: { - const modalList: AppModal[] = state.modals.slice() - if (modalList.length) { - const focusModal = modalList[0] // extract the next modal from the list - return { ...state, modals: modalList, focusModal } - } else { - return { ...state, modals: modalList } + } + case modalActionTypes.handleHideModal: { + setTimeout(() => { + if (state.focusModal.hideFn) { + state.focusModal.hideFn() } - } - case modalActionTypes.setToast: { - const toasterList = state.toasters.slice() - toasterList.push(action.payload) - if (toasterList.length === 1) { - return { ...state, toasters: toasterList, focusToaster: action.payload } - } else { - return { ...state, toasters: toasterList } + if (state.focusModal.resolve) { + state.focusModal.resolve(undefined) } - } - case modalActionTypes.handleToaster: { - const toasterList = state.toasters.slice() - toasterList.shift() - if (toasterList.length) { - const toaster = toasterList[0] - return { ...state, toasters: toasterList, focusToaster: toaster } - } else { - return { ...state, toasters: [] } + if (state.focusModal.next) { + state.focusModal.next() } + }, 250) + const modalList: AppModal[] = state.modals.slice() + modalList.shift() // remove the current modal from the list + state.focusModal = { ...state.focusModal, hide: true, message: null } + return { ...state, modals: modalList } + } + case modalActionTypes.processQueue: { + const modalList: AppModal[] = state.modals.slice() + if (modalList.length) { + const focusModal = modalList[0] // extract the next modal from the list + return { ...state, modals: modalList, focusModal } + } else { + return { ...state, modals: modalList } + } + } + case modalActionTypes.setToast: { + const toasterList = state.toasters.slice() + toasterList.push(action.payload) + if (toasterList.length === 1) { + return { ...state, toasters: toasterList, focusToaster: action.payload } + } else { + return { ...state, toasters: toasterList } } } + case modalActionTypes.handleToaster: { + const toasterList = state.toasters.slice() + toasterList.shift() + if (toasterList.length) { + const toaster = toasterList[0] + return { ...state, toasters: toasterList, focusToaster: toaster } + } else { + return { ...state, toasters: [] } + } + } + } } diff --git a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx index 8d07ce8f5b..fff40c6683 100644 --- a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx @@ -1,10 +1,10 @@ -import React, { useEffect, useRef, useState } from 'react' +import React, {useEffect, useRef, useState} from 'react' import './style/remix-app.css' -import { RemixUIMainPanel } from '@remix-ui/panel' +import {RemixUIMainPanel} from '@remix-ui/panel' import MatomoDialog from './components/modals/matomo' import OriginWarning from './components/modals/origin-warning' import DragBar from './components/dragbar/dragbar' -import { AppProvider } from './context/provider' +import {AppProvider} from './context/provider' import AppDialogs from './components/modals/dialogs' import DialogViewPlugin from './components/modals/dialogViewPlugin' import { AppContext } from './context/context' @@ -21,11 +21,14 @@ const RemixApp = (props: IRemixAppUi) => { const [hideSidePanel, setHideSidePanel] = useState(false) const [maximiseTrigger, setMaximiseTrigger] = useState(0) const [resetTrigger, setResetTrigger] = useState(0) - const [locale, setLocale] = useState<{ code:string; messages:any }>({ code:'en', messages:{} }); + const [locale, setLocale] = useState<{code: string; messages: any}>({ + code: 'en', + messages: {} + }) const sidePanelRef = useRef(null) useEffect(() => { - async function activateApp () { + async function activateApp() { props.app.themeModule.initTheme(() => { setAppReady(true) props.app.activate() @@ -38,9 +41,9 @@ const RemixApp = (props: IRemixAppUi) => { } }, []) - function setListeners () { + function setListeners() { props.app.sidePanel.events.on('toggle', () => { - setHideSidePanel(prev => { + setHideSidePanel((prev) => { return !prev }) }) @@ -56,13 +59,13 @@ const RemixApp = (props: IRemixAppUi) => { }) props.app.layout.event.on('maximisesidepanel', () => { - setMaximiseTrigger(prev => { + setMaximiseTrigger((prev) => { return prev + 1 }) }) props.app.layout.event.on('resetsidepanel', () => { - setResetTrigger(prev => { + setResetTrigger((prev) => { return prev + 1 }) }) @@ -86,17 +89,24 @@ const RemixApp = (props: IRemixAppUi) => {
-
{props.app.menuicons.render()}
-
{props.app.sidePanel.render()}
- -
+
+ {props.app.menuicons.render()} +
+
+ {props.app.sidePanel.render()} +
+ +
- -
+ }> +
diff --git a/libs/remix-ui/checkbox/src/lib/remix-ui-checkbox.tsx b/libs/remix-ui/checkbox/src/lib/remix-ui-checkbox.tsx index a70892796f..1722ffe42e 100644 --- a/libs/remix-ui/checkbox/src/lib/remix-ui-checkbox.tsx +++ b/libs/remix-ui/checkbox/src/lib/remix-ui-checkbox.tsx @@ -1,8 +1,7 @@ -import { CustomTooltip } from '@remix-ui/helper'; -import React, { CSSProperties } from 'react' //eslint-disable-line +import {CustomTooltip} from '@remix-ui/helper' +import React, {CSSProperties} from 'react' //eslint-disable-line import './remix-ui-checkbox.css' -type Placement = import('react-overlays/usePopper').Placement; - +type Placement = import('react-overlays/usePopper').Placement /* eslint-disable-next-line */ export interface RemixUiCheckboxProps { @@ -38,27 +37,23 @@ export const RemixUiCheckbox = ({ optionalClassName = '', display = 'flex', disabled, - tooltipPlacement = 'right', + tooltipPlacement = 'right' }: RemixUiCheckboxProps) => { - const childJSXWithTooltip = ( - +
-
- -
+ ), + placement: 'top-start', + tagId: 'intobackTooltip', + tooltipMsg: intl.formatMessage({id: 'debugger.stepBack'}) + }, + + stepIntoJSX: { markup: ( -
{ stepIntoForward && stepIntoForward() }} data-id="buttonNavigatorIntoForward" id="buttonNavigatorIntoFowardContainer"> - -
- ), - placement: 'top-start', - tagId: 'intoforwardTooltip', - tooltipMsg: 'Step into' - }, - stepOverForwardJSX : { + +
+ ), + placement: 'top-start', + tagId: 'intoforwardTooltip', + tooltipMsg: intl.formatMessage({id: 'debugger.stepInto'}) + }, + stepOverForwardJSX: { markup: ( -
{ stepOverForward && stepOverForward() }} data-id="buttonNavigatorOverForward" id="buttonNavigatorOverForwardContainer"> - -
- ), - placement: 'top-end', - tagId: 'overbackTooltip', - tooltipMsg: 'Step over forward', + +
+ ), + placement: 'top-end', + tagId: 'overbackTooltip', + tooltipMsg: intl.formatMessage({id: 'debugger.stepOverForward'}) + } } -} const jumpMarkupStructure = { - jumpPreviousBreakpointJSX : { + jumpPreviousBreakpointJSX: { markup: ( -
{ jumpPreviousBreakpoint && jumpPreviousBreakpoint() }} data-id="buttonNavigatorJumpPreviousBreakpoint"> - -
- ), - placement: 'bottom-start', - tagId: 'jumppreviousbreakpointTooltip', - tooltipMsg: 'Jump to the previous breakpoint' - }, - jumpOutJSX : { +
{ + jumpPreviousBreakpoint && jumpPreviousBreakpoint() + }} + data-id="buttonNavigatorJumpPreviousBreakpoint" + > + +
+ ), + placement: 'bottom-start', + tagId: 'jumppreviousbreakpointTooltip', + tooltipMsg: intl.formatMessage({id: 'debugger.jumpPreviousBreakpoint'}) + }, + jumpOutJSX: { markup: ( -
{ jumpOut && jumpOut() }} data-id="buttonNavigatorJumpOut" id="buttonNavigatorJumpOutContainer"> - -
- ), - placement: 'bottom-end', - tagId: 'jumpoutTooltip', - tooltipMsg: 'Jump out' +
{ + jumpOut && jumpOut() + }} + data-id="buttonNavigatorJumpOut" + id="buttonNavigatorJumpOutContainer" + > + +
+ ), + placement: 'bottom-end', + tagId: 'jumpoutTooltip', + tooltipMsg: intl.formatMessage({id: 'debugger.jumpOut'}) }, - jumpNextBreakpointJSX : { + jumpNextBreakpointJSX: { markup: ( -
{ jumpNextBreakpoint && jumpNextBreakpoint() }} data-id="buttonNavigatorJumpNextBreakpoint" id="buttonNavigatorJumpNextBreakpointContainer"> - -
- ), - placement: 'bottom-end', +
{ + jumpNextBreakpoint && jumpNextBreakpoint() + }} + data-id="buttonNavigatorJumpNextBreakpoint" + id="buttonNavigatorJumpNextBreakpointContainer" + > + +
+ ), + placement: 'bottom-end', tagId: 'jumpnextbreakpointTooltip', - tooltipMsg: 'Jump to the next breakpoint' + tooltipMsg: intl.formatMessage({id: 'debugger.jumpNextBreakpoint'}) } } return (
-
- { - Object.keys(stepMarkupStructure).map(x => ( - - {stepMarkupStructure[x].markup} - - )) - } +
+ {Object.keys(stepMarkupStructure).map((x) => ( + + {stepMarkupStructure[x].markup} + + ))}
-
- { - Object.keys(jumpMarkupStructure).map(x => ( - - {jumpMarkupStructure[x].markup} - - )) - } +
+ {Object.keys(jumpMarkupStructure).map((x) => ( + + {jumpMarkupStructure[x].markup} + + ))}
-
- This call has reverted, state changes made during the call will be reverted. - This call will run out of gas. - The parent call will throw an exception -
Click { jumpToException && jumpToException() }}>here to jump where the call reverted.
+
+ This call has reverted, state changes made during the call will be reverted. + + This call will run out of gas. + + + The parent call will throw an exception + +
+ Click{' '} + { + jumpToException && jumpToException() + }} + > + here + {' '} + to jump where the call reverted. +
) diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx index d651e8e16c..73333e01a5 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx @@ -1,18 +1,19 @@ -import React, { useState, useEffect, useRef } from 'react' // eslint-disable-line -import { FormattedMessage } from 'react-intl' +import React, {useState, useEffect, useRef} from 'react' // eslint-disable-line +import {FormattedMessage, useIntl} from 'react-intl' import TxBrowser from './tx-browser/tx-browser' // eslint-disable-line import StepManager from './step-manager/step-manager' // eslint-disable-line import VmDebugger from './vm-debugger/vm-debugger' // eslint-disable-line import VmDebuggerHead from './vm-debugger/vm-debugger-head' // eslint-disable-line -import { TransactionDebugger as Debugger } from '@remix-project/remix-debug' // eslint-disable-line -import { DebuggerUIProps } from './idebugger-api' // eslint-disable-line -import { Toaster } from '@remix-ui/toaster' // eslint-disable-line -import { CustomTooltip, isValidHash } from '@remix-ui/helper' +import {TransactionDebugger as Debugger} from '@remix-project/remix-debug' // eslint-disable-line +import {DebuggerUIProps} from './idebugger-api' // eslint-disable-line +import {Toaster} from '@remix-ui/toaster' // eslint-disable-line +import {CustomTooltip, isValidHash} from '@remix-ui/helper' /* eslint-disable-next-line */ import './debugger-ui.css' -const _paq = (window as any)._paq = (window as any)._paq || [] +const _paq = ((window as any)._paq = (window as any)._paq || []) export const DebuggerUI = (props: DebuggerUIProps) => { + const intl = useIntl() const debuggerModule = props.debuggerAPI const [state, setState] = useState({ isActive: false, @@ -54,7 +55,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { const handleResize = () => { if (panelsRef.current && debuggerTopRef.current) { - panelsRef.current.style.height = (window.innerHeight - debuggerTopRef.current.clientHeight) - debuggerTopRef.current.offsetTop - 7 +'px' + panelsRef.current.style.height = window.innerHeight - debuggerTopRef.current.clientHeight - debuggerTopRef.current.offsetTop - 7 + 'px' } } @@ -65,8 +66,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { useEffect(() => { window.addEventListener('resize', handleResize) // TODO: not a good way to wait on the ref doms element to be rendered of course - setTimeout(() => - handleResize(), 2000) + setTimeout(() => handleResize(), 2000) return () => window.removeEventListener('resize', handleResize) }, [state.debugging, state.isActive]) @@ -85,11 +85,15 @@ export const DebuggerUI = (props: DebuggerUIProps) => { useEffect(() => { const setEditor = () => { debuggerModule.onBreakpointCleared((fileName, row) => { - if (state.debugger) state.debugger.breakPointManager.remove({ fileName: fileName, row: row }) + if (state.debugger) + state.debugger.breakPointManager.remove({ + fileName: fileName, + row: row + }) }) debuggerModule.onBreakpointAdded((fileName, row) => { - if (state.debugger) state.debugger.breakPointManager.add({ fileName: fileName, row: row }) + if (state.debugger) state.debugger.breakPointManager.add({fileName: fileName, row: row}) }) debuggerModule.onEditorContentChanged(() => { @@ -101,9 +105,9 @@ export const DebuggerUI = (props: DebuggerUIProps) => { const providerChanged = () => { debuggerModule.onEnvChanged((provider) => { - setState(prevState => { + setState((prevState) => { const isLocalNodeUsed = !provider.startsWith('vm') && provider !== 'injected' - return { ...prevState, isLocalNodeUsed: isLocalNodeUsed } + return {...prevState, isLocalNodeUsed: isLocalNodeUsed} }) }) } @@ -116,34 +120,38 @@ export const DebuggerUI = (props: DebuggerUIProps) => { debuggerInstance.event.register('debuggerStatus', async (isActive) => { await debuggerModule.discardHighlight() - setState(prevState => { - return { ...prevState, isActive } + setState((prevState) => { + return {...prevState, isActive} }) }) debuggerInstance.event.register('locatingBreakpoint', async (isActive) => { - setState(prevState => { - return { ...prevState, sourceLocationStatus: 'Locating breakpoint, this might take a while...' } + setState((prevState) => { + return { + ...prevState, + sourceLocationStatus: intl.formatMessage({id: 'debugger.sourceLocationStatus1'}) + } }) }) debuggerInstance.event.register('noBreakpointHit', async (isActive) => { - setState(prevState => { - return { ...prevState, sourceLocationStatus: '' } + setState((prevState) => { + return {...prevState, sourceLocationStatus: ''} }) }) debuggerInstance.event.register('newSourceLocation', async (lineColumnPos, rawLocation, generatedSources, address, stepDetail, lineGasCost) => { if (!lineColumnPos) { await debuggerModule.discardHighlight() - setState(prevState => { - return { ...prevState, sourceLocationStatus: 'Source location not available, neither in Sourcify nor in Etherscan. Please make sure the Etherscan api key is provided in the settings.' } + setState((prevState) => { + return { + ...prevState, + sourceLocationStatus: intl.formatMessage({id: 'debugger.sourceLocationStatus2'}) + } }) return } - const contracts = await debuggerModule.fetchContractAndCompile( - address || currentReceipt.contractAddress || currentReceipt.to, - currentReceipt) + const contracts = await debuggerModule.fetchContractAndCompile(address || currentReceipt.contractAddress || currentReceipt.to, currentReceipt) if (contracts) { let path = contracts.getSourceName(rawLocation.file) if (!path) { @@ -155,7 +163,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { try { content = await debuggerModule.getFile(path) } catch (e) { - const message = 'Unable to fetch generated sources, the file probably doesn\'t exist yet.' + const message = "Unable to fetch generated sources, the file probably doesn't exist yet." console.log(message, ' ', e) } if (content !== source.contents) { @@ -166,8 +174,8 @@ export const DebuggerUI = (props: DebuggerUIProps) => { } } if (path) { - setState(prevState => { - return { ...prevState, sourceLocationStatus: '' } + setState((prevState) => { + return {...prevState, sourceLocationStatus: ''} }) await debuggerModule.discardHighlight() await debuggerModule.highlight(lineColumnPos, path, rawLocation, stepDetail, lineGasCost) @@ -183,7 +191,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { } const updateTxNumberFlag = (empty: boolean) => { - setState(prevState => { + setState((prevState) => { return { ...prevState, txNumberIsEmpty: empty, @@ -194,7 +202,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { const unloadRequested = (blockNumber, txIndex, tx) => { unLoad() - setState(prevState => { + setState((prevState) => { return { ...prevState, sourceLocationStatus: '' @@ -205,7 +213,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { const unLoad = () => { debuggerModule.onStopDebugging() if (state.debugger) state.debugger.unload() - setState(prevState => { + setState((prevState) => { return { ...prevState, isActive: false, @@ -228,10 +236,10 @@ export const DebuggerUI = (props: DebuggerUIProps) => { const startDebugging = async (blockNumber, txNumber, tx, optWeb3?) => { if (state.debugger) { unLoad() - await (new Promise((resolve) => setTimeout(() => resolve({}), 1000))) + await new Promise((resolve) => setTimeout(() => resolve({}), 1000)) } if (!txNumber) return - setState(prevState => { + setState((prevState) => { return { ...prevState, txNumber: txNumber, @@ -239,7 +247,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { } }) if (!isValidHash(txNumber)) { - setState(prevState => { + setState((prevState) => { return { ...prevState, validationError: 'Invalid transaction hash.' @@ -253,7 +261,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { const networkId = await web3.eth.net.getId() _paq.push(['trackEvent', 'debugger', 'startDebugging', networkId]) if (networkId === 42) { - setState(prevState => { + setState((prevState) => { return { ...prevState, validationError: 'Unfortunately, the Kovan network is not supported.' @@ -272,7 +280,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { currentBlock = await web3.eth.getBlock(currentReceipt.blockHash) currentTransaction = await web3.eth.getTransaction(txNumber) } catch (e) { - setState(prevState => { + setState((prevState) => { return { ...prevState, validationError: e.message @@ -298,12 +306,12 @@ export const DebuggerUI = (props: DebuggerUIProps) => { debugWithGeneratedSources: state.opt.debugWithGeneratedSources }) - setTimeout(async() => { + setTimeout(async () => { debuggerModule.onStartDebugging(debuggerInstance) try { await debuggerInstance.debug(blockNumber, txNumber, tx, () => { listenToEvents(debuggerInstance, currentReceipt) - setState(prevState => { + setState((prevState) => { return { ...prevState, blockNumber, @@ -320,7 +328,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { }) } catch (error) { unLoad() - setState(prevState => { + setState((prevState) => { let errorMsg = error.message || error if (typeof errorMsg !== 'string') { errorMsg = JSON.stringify(errorMsg) + '. Possible error: the current endpoint does not support retrieving the trace of a transaction.' @@ -338,7 +346,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { } const debug = (txHash, web3?) => { - setState(prevState => { + setState((prevState) => { return { ...prevState, validationError: '', @@ -370,16 +378,22 @@ export const DebuggerUI = (props: DebuggerUIProps) => { const customJSX = ( - { - setState(prevState => { - return { ...prevState, opt: { ...prevState.opt, debugWithGeneratedSources: checked } } - }) - }} type="checkbox" /> - ) @@ -389,50 +403,74 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
- } - placement="bottom-start" - > + } placement="bottom-start"> {customJSX}
- { state.isLocalNodeUsed &&
- - { - setState(prevState => { - return { ...prevState, opt: { ...prevState.opt, debugWithLocalNode: checked } } - }) - }} - type="checkbox" - /> - - -
- } - { state.validationError && {state.validationError} } + {state.isLocalNodeUsed && ( +
+ } placement="right"> + { + setState((prevState) => { + return { + ...prevState, + opt: {...prevState.opt, debugWithLocalNode: checked} + } + }) + }} + type="checkbox" + /> + + +
+ )} + {state.validationError && {state.validationError}}
- - { state.debugging && state.sourceLocationStatus &&
{state.sourceLocationStatus}
} - { !state.debugging && - } - { state.debugging && } + + {state.debugging && state.sourceLocationStatus && ( +
+ {state.sourceLocationStatus} +
+ )} + {!state.debugging && ( +
+ + + :{' '} + + + {' '} + &{' '} + + https://etherscan.io/contractsVerified + + +
+ )} + {state.debugging && }
- { state.debugging && } - { state.debugging && } + {state.debugging && } + {state.debugging && ( + + )}
) diff --git a/libs/remix-ui/debugger-ui/src/lib/slider/slider.tsx b/libs/remix-ui/debugger-ui/src/lib/slider/slider.tsx index b49a104456..517bbfe87a 100644 --- a/libs/remix-ui/debugger-ui/src/lib/slider/slider.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/slider/slider.tsx @@ -1,6 +1,6 @@ -import React, { useState, useEffect, useRef } from 'react' // eslint-disable-line +import React, {useState, useEffect, useRef} from 'react' // eslint-disable-line -export const Slider = ({ jumpTo, sliderValue, traceLength }) => { +export const Slider = ({jumpTo, sliderValue, traceLength}) => { const onChangeId = useRef(null) const slider = useRef(null) @@ -9,13 +9,13 @@ export const Slider = ({ jumpTo, sliderValue, traceLength }) => { }, [sliderValue]) const setValue = (value) => { - if (value < 0) return + if (value < 0) return if (value === slider.current.value) return slider.current.value = value if (onChangeId.current) { clearTimeout(onChangeId.current) } - ((value) => { + ;((value) => { onChangeId.current = setTimeout(() => { jumpTo && jumpTo(value) }, 100) @@ -30,11 +30,12 @@ export const Slider = ({ jumpTo, sliderValue, traceLength }) => { return (
- { +export const StepManager = ({ + stepManager: { + jumpTo, + traceLength, + stepIntoBack, + stepIntoForward, + stepOverBack, + stepOverForward, + jumpOut, + jumpNextBreakpoint, + jumpPreviousBreakpoint, + jumpToException, + registerEvent + } +}) => { const [state, setState] = useState({ sliderValue: -1, revertWarning: '', @@ -16,17 +30,17 @@ export const StepManager = ({ stepManager: { jumpTo, traceLength, stepIntoBack, }, [registerEvent]) const setRevertWarning = (warning) => { - setState(prevState => { - return { ...prevState, revertWarning: warning } + setState((prevState) => { + return {...prevState, revertWarning: warning} }) } const updateStep = (step, stepState, jumpOutDisabled) => { - setState(prevState => { - return { ...prevState, sliderValue: step, stepState, jumpOutDisabled } + setState((prevState) => { + return {...prevState, sliderValue: step, stepState, jumpOutDisabled} }) } - const { sliderValue, revertWarning, stepState, jumpOutDisabled } = state + const {sliderValue, revertWarning, stepState, jumpOutDisabled} = state return (
diff --git a/libs/remix-ui/debugger-ui/src/lib/tx-browser/tx-browser.tsx b/libs/remix-ui/debugger-ui/src/lib/tx-browser/tx-browser.tsx index bc25a233bb..2e07121534 100644 --- a/libs/remix-ui/debugger-ui/src/lib/tx-browser/tx-browser.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/tx-browser/tx-browser.tsx @@ -1,11 +1,12 @@ -import { CustomTooltip } from '@remix-ui/helper' -import React, { useState, useEffect, useRef } from 'react' //eslint-disable-line -import { useIntl, FormattedMessage } from 'react-intl' +import {CustomTooltip, isValidHash} from '@remix-ui/helper' +import React, {useState, useEffect, useRef} from 'react' //eslint-disable-line +import {useIntl, FormattedMessage} from 'react-intl' import './tx-browser.css' -export const TxBrowser = ({ requestDebug, updateTxNumberFlag, unloadRequested, transactionNumber, debugging }) => { +export const TxBrowser = ({requestDebug, updateTxNumberFlag, unloadRequested, transactionNumber, debugging}) => { const [state, setState] = useState({ - txNumber: '' + txNumber: '', + isTxNumberValid: false }) const inputValue = useRef(null) @@ -13,15 +14,17 @@ export const TxBrowser = ({ requestDebug, updateTxNumberFlag, unloadRequested, t const intl = useIntl() useEffect(() => { - setState(prevState => { + setState((prevState) => { return { ...prevState, - txNumber: transactionNumber + txNumber: transactionNumber, + isTxNumberValid: isValidHash(transactionNumber), } }) - }, [transactionNumber]) + }, [transactionNumber, debugging]) const handleSubmit = () => { + if (!state.txNumber || !state.isTxNumberValid) return if (debugging) { unload() } else { @@ -34,14 +37,10 @@ export const TxBrowser = ({ requestDebug, updateTxNumberFlag, unloadRequested, t } const txInputChanged = (value) => { - // todo check validation of txnumber in the input element, use - // required - // oninvalid="setCustomValidity('Please provide a valid transaction number, must start with 0x and have length of 22')" - // pattern="^0[x,X]+[0-9a-fA-F]{22}" - // this.state.txNumberInput.setCustomValidity('') - setState(prevState => { + setState((prevState) => { return { ...prevState, + isTxNumberValid: isValidHash(value), txNumber: value } }) @@ -50,41 +49,49 @@ export const TxBrowser = ({ requestDebug, updateTxNumberFlag, unloadRequested, t const txInputOnInput = () => { updateTxNumberFlag(!inputValue.current.value) } + const customJSX = ( -
- -
+
+ +
) return ( -
-
-
+
+
+
txInputChanged(value)} + className="form-control m-0 txinput" + id="txinput" + type="text" + onChange={({target: {value}}) => txInputChanged(value)} onInput={txInputOnInput} placeholder={intl.formatMessage({id: 'debugger.placeholder'})} - data-id='debuggerTransactionInput' + data-id="debuggerTransactionInput" disabled={debugging} />
-
+
} + tooltipText={} tooltipId={'debuggingButtontooltip'} tooltipClasses="text-nowrap" > @@ -92,7 +99,7 @@ export const TxBrowser = ({ requestDebug, updateTxNumberFlag, unloadRequested, t
- +
) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx index 50a6572c48..96c194e93f 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx @@ -1,8 +1,9 @@ -import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line -import { initialState, reducer } from '../../reducers/assembly-items' +import React, {useState, useRef, useEffect, useReducer} from 'react' // eslint-disable-line +import {FormattedMessage} from 'react-intl' +import {initialState, reducer} from '../../reducers/assembly-items' import './styles/assembly-items.css' -export const AssemblyItems = ({ registerEvent }) => { +export const AssemblyItems = ({registerEvent}) => { const [assemblyItems, dispatch] = useReducer(reducer, initialState) const [absoluteSelectedIndex, setAbsoluteSelectedIndex] = useState(0) const [selectedItem, setSelectedItem] = useState(0) @@ -14,13 +15,28 @@ export const AssemblyItems = ({ registerEvent }) => { const asmItemsRef = useRef(null) useEffect(() => { - registerEvent && registerEvent('codeManagerChanged', (code, address, index, nextIndexes, returnInstructionIndexes, outOfGasInstructionIndexes) => { - dispatch({ type: 'FETCH_OPCODES_SUCCESS', payload: { code, address, index, nextIndexes, returnInstructionIndexes, outOfGasInstructionIndexes } }) - }) + registerEvent && + registerEvent('codeManagerChanged', (code, address, index, nextIndexes, returnInstructionIndexes, outOfGasInstructionIndexes) => { + dispatch({ + type: 'FETCH_OPCODES_SUCCESS', + payload: { + code, + address, + index, + nextIndexes, + returnInstructionIndexes, + outOfGasInstructionIndexes + } + }) + }) - registerEvent && registerEvent('lineGasCostChanged', (instructionsIndexes: number[], line: []) => { - dispatch({ type: 'FETCH_INDEXES_FOR_NEW_LINE', payload: { currentLineIndexes: instructionsIndexes || [], line } }) - }) + registerEvent && + registerEvent('lineGasCostChanged', (instructionsIndexes: number[], line: []) => { + dispatch({ + type: 'FETCH_INDEXES_FOR_NEW_LINE', + payload: {currentLineIndexes: instructionsIndexes || [], line} + }) + }) }, []) useEffect(() => { @@ -128,17 +144,36 @@ export const AssemblyItems = ({ registerEvent }) => { return (
-
-
- { assemblyItems.display.length == 0 &&
No data available
} -
- { - assemblyItems.display.map((item, i) => { - return
{ refs.current[i] = ref }}> - {item}{assemblyItems.currentLineIndexes.includes(i) ? - LINE {assemblyItems.line + 1} : ' - '} +
+
+ {assemblyItems.display.length == 0 && ( +
+ +
+ )} +
+ {assemblyItems.display.map((item, i) => { + return ( +
{ + refs.current[i] = ref + }} + > + {item} + {assemblyItems.currentLineIndexes.includes(i) ? ( + + + - LINE {assemblyItems.line + 1} + + + ) : ( + ' - ' + )}
- }) - } + ) + })}
diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/calldata-panel.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/calldata-panel.tsx index c33dce048b..a7b01c5cc5 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/calldata-panel.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/calldata-panel.tsx @@ -1,10 +1,10 @@ import React from 'react' // eslint-disable-line import DropdownPanel from './dropdown-panel' // eslint-disable-line -export const CalldataPanel = ({ calldata, className = "" }) => { +export const CalldataPanel = ({calldata, className = ''}) => { return ( -
- +
+
) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/callstack-panel.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/callstack-panel.tsx index d1d40c8dbf..1636fdf67d 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/callstack-panel.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/callstack-panel.tsx @@ -1,10 +1,10 @@ import React from 'react' // eslint-disable-line import DropdownPanel from './dropdown-panel' // eslint-disable-line -export const CallstackPanel = ({ calldata, className }) => { +export const CallstackPanel = ({calldata, className}) => { return ( -
- +
+
) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/code-list-view.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/code-list-view.tsx index 657f5b6f07..da2b6b0b7d 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/code-list-view.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/code-list-view.tsx @@ -1,9 +1,9 @@ -import React, { useState, useEffect } from 'react' // eslint-disable-line +import React, {useState, useEffect} from 'react' // eslint-disable-line import AssemblyItems from './assembly-items' // eslint-disable-line -export const CodeListView = ({ registerEvent, className = ""}) => { +export const CodeListView = ({registerEvent, className = ''}) => { return ( -
+
) diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/dropdown-panel.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/dropdown-panel.tsx index 8fdd0ceee0..e5afecc66d 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/dropdown-panel.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/dropdown-panel.tsx @@ -1,26 +1,44 @@ -import React, { useState, useEffect, useReducer } from 'react' // eslint-disable-line -import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line -import { DropdownPanelProps, ExtractData, ExtractFunc } from '../../types' // eslint-disable-line -import { CopyToClipboard } from '@remix-ui/clipboard' // eslint-disable-line -import { initialState, reducer } from '../../reducers/calldata' +import React, {useState, useEffect, useReducer} from 'react' // eslint-disable-line +import {useIntl} from 'react-intl' +import {TreeView, TreeViewItem} from '@remix-ui/tree-view' // eslint-disable-line +import {DropdownPanelProps, ExtractData, ExtractFunc} from '../../types' // eslint-disable-line +import {CopyToClipboard} from '@remix-ui/clipboard' // eslint-disable-line +import {initialState, reducer} from '../../reducers/calldata' import './styles/dropdown-panel.css' export const DropdownPanel = (props: DropdownPanelProps) => { + const intl = useIntl() const [calldataObj, dispatch] = useReducer(reducer, initialState) - const { dropdownName, className, dropdownMessage, calldata, header, loading, extractFunc, formatSelfFunc, registerEvent, triggerEvent, loadMoreEvent, loadMoreCompletedEvent, headStyle, bodyStyle, hexHighlight } = props + const { + dropdownName, + className, + dropdownMessage, + calldata, + header, + loading, + extractFunc, + formatSelfFunc, + registerEvent, + triggerEvent, + loadMoreEvent, + loadMoreCompletedEvent, + headStyle, + bodyStyle, + hexHighlight + } = props const extractDataDefault: ExtractFunc = (item, parent?) => { const ret: ExtractData = {} if (item instanceof Array) { ret.children = item.map((item, index) => { - return { key: index, value: item } + return {key: index, value: item} }) ret.self = 'Array' ret.isNode = true ret.isLeaf = false } else if (item instanceof Object) { ret.children = Object.keys(item).map((key) => { - return { key: key, value: item[key] } + return {key: key, value: item[key]} }) ret.self = 'Object' ret.isNode = true @@ -35,14 +53,26 @@ export const DropdownPanel = (props: DropdownPanelProps) => { } const formatSelfDefault = (key: string | number, data: ExtractData) => { let value - if (hexHighlight && typeof (data.self) === 'string') { + if (hexHighlight && typeof data.self === 'string') { const isHex = data.self.startsWith('0x') || hexHighlight if (isHex) { const regex = /^(0+)(.*)/g const split = regex.exec(data.self.replace('0x', '')) if (split && split[1]) { - value = (0x{split[1]}{ split[2] && {split[2]} }) - } else value = (0x{data.self.replace('0x', '')}) + value = ( + + 0x + {split[1]} + {split[2] && {split[2]}} + + ) + } else + value = ( + + 0x + {data.self.replace('0x', '')} + + ) } else value = {data.self} } else value = {data.self} return ( @@ -56,7 +86,7 @@ export const DropdownPanel = (props: DropdownPanelProps) => { header: '', toggleDropdown: true, message: { - innerText: 'No data available.', + innerText: intl.formatMessage({id: 'debugger.noDataAvailable'}), display: 'block' }, dropdownContent: { @@ -74,13 +104,14 @@ export const DropdownPanel = (props: DropdownPanelProps) => { }) useEffect(() => { - registerEvent && registerEvent(loadMoreCompletedEvent, (updatedCalldata) => { - dispatch({ type: 'UPDATE_CALLDATA_SUCCESS', payload: updatedCalldata }) - }) + registerEvent && + registerEvent(loadMoreCompletedEvent, (updatedCalldata) => { + dispatch({type: 'UPDATE_CALLDATA_SUCCESS', payload: updatedCalldata}) + }) }, []) useEffect(() => { - dispatch({ type: 'FETCH_CALLDATA_SUCCESS', payload: calldata }) + dispatch({type: 'FETCH_CALLDATA_SUCCESS', payload: calldata}) }, [calldata]) useEffect(() => { @@ -96,7 +127,7 @@ export const DropdownPanel = (props: DropdownPanelProps) => { }, [loading]) const handleToggle = () => { - setState(prevState => { + setState((prevState) => { return { ...prevState, toggleDropdown: !prevState.toggleDropdown @@ -108,13 +139,13 @@ export const DropdownPanel = (props: DropdownPanelProps) => { if (!state.expandPath.includes(keyPath)) { state.expandPath.push(keyPath) } else { - state.expandPath = state.expandPath.filter(path => !path.startsWith(keyPath)) + state.expandPath = state.expandPath.filter((path) => !path.startsWith(keyPath)) } } const message = (message) => { if (message === state.message.innerText) return - setState(prevState => { + setState((prevState) => { return { ...prevState, message: { @@ -127,7 +158,7 @@ export const DropdownPanel = (props: DropdownPanelProps) => { } const setLoading = () => { - setState(prevState => { + setState((prevState) => { return { ...prevState, message: { @@ -150,7 +181,7 @@ export const DropdownPanel = (props: DropdownPanelProps) => { if (calldata && Array.isArray(calldata) && calldata.length === 0) isEmpty = true else if (calldata && Object.keys(calldata).length === 0 && calldata.constructor === Object) isEmpty = true - setState(prevState => { + setState((prevState) => { return { ...prevState, dropdownContent: { @@ -160,7 +191,7 @@ export const DropdownPanel = (props: DropdownPanelProps) => { // replace 0xNaN with 0x0 copiableContent: JSON.stringify(calldata, null, '\t').replace(/0xNaN/g, '0x0'), message: { - innerText: isEmpty ? 'No data available' : '', + innerText: isEmpty ? intl.formatMessage({id: 'debugger.noDataAvailable'}) : '', display: isEmpty ? 'block' : 'none' }, updating: false, @@ -173,48 +204,72 @@ export const DropdownPanel = (props: DropdownPanelProps) => { const renderData = (item: ExtractData, parent, key: string | number, keyPath: string) => { const data = extractFunc ? extractFunc(item, parent) : extractDataDefault(item, parent) const children = (data.children || []).map((child) => { - return ( - renderData(child.value, data, child.key, keyPath + '/' + child.key) - ) + return renderData(child.value, data, child.key, keyPath + '/' + child.key) }) if (children && children.length > 0) { return ( - handleExpand(keyPath)} expand={state.expandPath.includes(keyPath)}> + handleExpand(keyPath)} + expand={state.expandPath.includes(keyPath)} + > {children} - {data.hasNext && { triggerEvent(loadMoreEvent, [data.cursor]) }} />} + {data.hasNext && ( + { + triggerEvent(loadMoreEvent, [data.cursor]) + }} + /> + )} ) } else { - return handleExpand(keyPath)} expand={state.expandPath.includes(keyPath)} /> + return ( + handleExpand(keyPath)} + expand={state.expandPath.includes(keyPath)} + /> + ) } } const uniquePanelName = dropdownName.split(' ').join('') return ( -
+
-
{dropdownName}
{header} - +
+ {dropdownName} +
+ + {header} + +
-
- -
- { - state.data && - - { - Object.keys(state.data).map((innerkey) => renderData(state.data[innerkey], state.data, innerkey, innerkey)) - } - - } +
+ +
+ {state.data && {Object.keys(state.data).map((innerkey) => renderData(state.data[innerkey], state.data, innerkey, innerkey))}} +
+ +
+ {state.message.innerText}
- -
{state.message.innerText}
) diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/full-storages-changes.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/full-storages-changes.tsx index acfe871891..46ef22dbbd 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/full-storages-changes.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/full-storages-changes.tsx @@ -1,10 +1,10 @@ import React from 'react' // eslint-disable-line -import { DropdownPanel } from './dropdown-panel' // eslint-disable-line +import {DropdownPanel} from './dropdown-panel' // eslint-disable-line -export const FullStoragesChanges = ({ calldata, className = "" }) => { +export const FullStoragesChanges = ({calldata, className = ''}) => { return ( -
- +
+
) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx index d3544f7cbe..6450536f5a 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx @@ -1,8 +1,8 @@ -import React, { useState, useEffect } from 'react' // eslint-disable-line +import React, {useState, useEffect} from 'react' // eslint-disable-line import DropdownPanel from './dropdown-panel' // eslint-disable-line -import { default as deepequal } from 'deep-equal' // eslint-disable-line +import {default as deepequal} from 'deep-equal' // eslint-disable-line -export const FunctionPanel = ({ data, className }) => { +export const FunctionPanel = ({data, className}) => { const [calldata, setCalldata] = useState(null) useEffect(() => { @@ -10,8 +10,8 @@ export const FunctionPanel = ({ data, className }) => { }, [data]) return ( -
- +
+
) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/global-variables.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/global-variables.tsx index ed5f4aec0a..9c01778615 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/global-variables.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/global-variables.tsx @@ -1,9 +1,9 @@ import React from 'react' // eslint-disable-line import DropdownPanel from './dropdown-panel' // eslint-disable-line -import { BN } from 'bn.js' +import {BN} from 'bn.js' import Web3 from 'web3' -export const GlobalVariables = ({ block, receipt, tx, className }) => { +export const GlobalVariables = ({block, receipt, tx, className}) => { // see https://docs.soliditylang.org/en/latest/units-and-global-variables.html#block-and-transaction-properties const globals = { 'block.chainid': tx && tx.chainId, @@ -14,7 +14,7 @@ export const GlobalVariables = ({ block, receipt, tx, className }) => { 'block.timestamp': block && block.timestamp, 'msg.sender': tx && tx.from, 'msg.sig': tx && tx.input && tx.input.substring(0, 10), - 'msg.value': tx && (tx.value + ' Wei'), + 'msg.value': tx && tx.value + ' Wei', 'tx.origin': tx && tx.from } if (block && block.baseFeePerGas) { @@ -22,8 +22,8 @@ export const GlobalVariables = ({ block, receipt, tx, className }) => { } return ( -
- +
+
) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/memory-panel.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/memory-panel.tsx index 10931a103a..b92df380ed 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/memory-panel.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/memory-panel.tsx @@ -1,10 +1,10 @@ import React from 'react' // eslint-disable-line import DropdownPanel from './dropdown-panel' // eslint-disable-line -export const MemoryPanel = ({ calldata, className}) => { +export const MemoryPanel = ({calldata, className}) => { return ( -
- +
+
) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-locals.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-locals.tsx index 51913796af..99aa7e8609 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-locals.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-locals.tsx @@ -1,9 +1,9 @@ -import React, { useState, useEffect } from 'react' // eslint-disable-line +import React, {useState, useEffect} from 'react' // eslint-disable-line import DropdownPanel from './dropdown-panel' // eslint-disable-line -import { extractData } from '../../utils/solidityTypeFormatter' // eslint-disable-line -import { ExtractData } from '../../types' // eslint-disable-line +import {extractData} from '../../utils/solidityTypeFormatter' // eslint-disable-line +import {ExtractData} from '../../types' // eslint-disable-line -export const SolidityLocals = ({ data, message, registerEvent, triggerEvent, className = "" }) => { +export const SolidityLocals = ({data, message, registerEvent, triggerEvent, className = ''}) => { const [calldata, setCalldata] = useState(null) useEffect(() => { @@ -14,46 +14,46 @@ export const SolidityLocals = ({ data, message, registerEvent, triggerEvent, cla let color = 'var(--primary)' if (data.isArray || data.isStruct || data.isMapping) { color = 'var(--info)' - } else if ( - data.type.indexOf('uint') === 0 || - data.type.indexOf('int') === 0 || - data.type.indexOf('bool') === 0 || - data.type.indexOf('enum') === 0 - ) { + } else if (data.type.indexOf('uint') === 0 || data.type.indexOf('int') === 0 || data.type.indexOf('bool') === 0 || data.type.indexOf('enum') === 0) { color = 'var(--green)' } else if (data.type === 'string') { color = 'var(--teal)' - } else if (data.self == 0x0) { // eslint-disable-line + } else if (data.self == 0x0) { + // eslint-disable-line color = 'var(--gray)' } if (data.type === 'string') { data.self = JSON.stringify(data.self) } return ( -