Merge remote-tracking branch 'upstream/master' into spacesailor24/web3js-v4-upgrade

pull/3951/head
Oleksii Kosynskyi 1 year ago
commit d15c3b3f2d
No known key found for this signature in database
GPG Key ID: B4A8D3CCE22EA65E
  1. 36
      .circleci/config.yml
  2. 2
      .husky/pre-commit
  3. 3
      .lintstagedrc.json
  4. 9
      .prettierrc.json
  5. 6
      README.md
  6. 59
      apps/circuit-compiler/project.json
  7. 17
      apps/circuit-compiler/src/app/app.tsx
  8. 224
      apps/circuit-compiler/src/app/services/circomPluginClient.ts
  9. 0
      apps/circuit-compiler/src/css/app.css
  10. 11
      apps/circuit-compiler/src/example/simple.circom
  11. 15
      apps/circuit-compiler/src/index.html
  12. 8
      apps/circuit-compiler/src/main.tsx
  13. 7
      apps/circuit-compiler/src/polyfills.ts
  14. 17
      apps/circuit-compiler/src/profile.json
  15. 24
      apps/circuit-compiler/tsconfig.app.json
  16. 17
      apps/circuit-compiler/tsconfig.json
  17. 92
      apps/circuit-compiler/webpack.config.js
  18. 64
      apps/etherscan/src/app/utils/networks.ts
  19. 4
      apps/remix-ide-e2e/src/commands/checkAnnotations.ts
  20. 2
      apps/remix-ide-e2e/src/commands/checkAnnotationsNotPresent.ts
  21. 70
      apps/remix-ide-e2e/src/tests/editor.test.ts
  22. 77
      apps/remix-ide-e2e/src/tests/editorHoverContext.test.ts
  23. 30
      apps/remix-ide-e2e/src/tests/editorReferences.test.ts
  24. 12
      apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts
  25. 120
      apps/remix-ide-e2e/src/types/index.d.ts
  26. 2
      apps/remix-ide/project.json
  27. 4
      apps/remix-ide/release-process.md
  28. 129
      apps/remix-ide/src/app.js
  29. 10
      apps/remix-ide/src/app/editor/editor.js
  30. 47
      apps/remix-ide/src/app/files/fileManager.ts
  31. 8
      apps/remix-ide/src/app/panels/layout.ts
  32. 47
      apps/remix-ide/src/app/plugins/openaigpt.tsx
  33. 56
      apps/remix-ide/src/app/plugins/parser/code-parser.tsx
  34. 7
      apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts
  35. 5
      apps/remix-ide/src/app/plugins/parser/services/code-parser-gas-service.ts
  36. 4
      apps/remix-ide/src/app/providers/injected-arbitrum-one-provider.tsx
  37. 27
      apps/remix-ide/src/app/providers/injected-custom-provider.tsx
  38. 30
      apps/remix-ide/src/app/providers/injected-ephemery-testnet-provider.tsx
  39. 4
      apps/remix-ide/src/app/providers/injected-optimism-provider.tsx
  40. 27
      apps/remix-ide/src/app/providers/injected-skale-chaos-testnet-provider.tsx
  41. 40
      apps/remix-ide/src/app/udapp/run-tab.js
  42. 144
      apps/remix-ide/src/remixAppManager.js
  43. 1
      apps/remix-ide/src/remixEngine.js
  44. 24
      apps/remix-ide/team-best-practices.md
  45. 77
      apps/walletconnect/src/services/WalletConnectRemixClient.ts
  46. 9
      libs/ghaction-helper/package.json
  47. 2
      libs/remix-analyzer/README.md
  48. 8
      libs/remix-analyzer/package.json
  49. 2
      libs/remix-astwalker/README.md
  50. 6
      libs/remix-astwalker/package.json
  51. 4
      libs/remix-debug/README.md
  52. 12
      libs/remix-debug/package.json
  53. 2
      libs/remix-debug/src/init.ts
  54. 2
      libs/remix-lib/README.md
  55. 4
      libs/remix-lib/package.json
  56. 2
      libs/remix-simulator/README.md
  57. 15
      libs/remix-simulator/bin/ethsim
  58. 6
      libs/remix-simulator/package.json
  59. 6
      libs/remix-solidity/package.json
  60. 21
      libs/remix-solidity/src/compiler/compiler.ts
  61. 2
      libs/remix-solidity/src/compiler/types.ts
  62. 10
      libs/remix-tests/package.json
  63. 114
      libs/remix-ui/editor/src/lib/providers/codeActionProvider.ts
  64. 14
      libs/remix-ui/editor/src/lib/providers/completion/completionGlobals.ts
  65. 82
      libs/remix-ui/editor/src/lib/providers/quickfixes.ts
  66. 6
      libs/remix-ui/editor/src/lib/remix-ui-editor.css
  67. 138
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  68. 7288
      libs/remix-ui/editor/src/types/monaco.ts
  69. 8
      libs/remix-ui/helper/src/lib/helper-components.tsx
  70. 2
      libs/remix-ui/home-tab/src/lib/components/homeTabFeaturedPlugins.tsx
  71. 16
      libs/remix-ui/renderer/src/lib/renderer.tsx
  72. 42
      libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
  73. 2
      libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx
  74. 4
      libs/remix-ui/run-tab/src/lib/css/run-tab.css
  75. 2
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  76. 32
      libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx
  77. 2
      libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx
  78. 17
      libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts
  79. 125
      libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
  80. 3
      libs/remix-ui/terminal/src/lib/types/terminalTypes.ts
  81. 2
      libs/remix-url-resolver/README.md
  82. 4
      libs/remix-url-resolver/package.json
  83. 2
      libs/remix-ws-templates/README.md
  84. 4
      libs/remix-ws-templates/package.json
  85. 304
      libs/remix-ws-templates/src/script-templates/contract-deployer/create2-factory-deploy.ts
  86. 2
      libs/remixd/README.md
  87. 20
      package.json
  88. 0
      pkg/index.js
  89. 3
      removedlintstagedrc.json
  90. 277
      yarn.lock

@ -5,7 +5,7 @@ parameters:
type: boolean type: boolean
default: false default: false
orbs: orbs:
browser-tools: circleci/browser-tools@1.4.3 browser-tools: circleci/browser-tools@1.4.4
jobs: jobs:
build: build:
docker: docker:
@ -144,8 +144,9 @@ jobs:
- browser-tools/install-browser-tools: - browser-tools/install-browser-tools:
install-firefox: false install-firefox: false
install-chrome: true install-chrome: true
install-chromedriver: false
install-geckodriver: false install-geckodriver: false
install-chromedriver: true - install-chromedriver-custom-linux
- run: google-chrome --version - run: google-chrome --version
- run: chromedriver --version - run: chromedriver --version
- run: rm LICENSE.chromedriver 2> /dev/null || true - run: rm LICENSE.chromedriver 2> /dev/null || true
@ -202,7 +203,8 @@ jobs:
install-firefox: false install-firefox: false
install-chrome: true install-chrome: true
install-geckodriver: false install-geckodriver: false
install-chromedriver: true install-chromedriver: false
- install-chromedriver-custom-linux
- run: google-chrome --version - run: google-chrome --version
- run: chromedriver --version - run: chromedriver --version
- run: rm LICENSE.chromedriver 2> /dev/null || true - run: rm LICENSE.chromedriver 2> /dev/null || true
@ -367,3 +369,31 @@ workflows:
only: remix_beta only: remix_beta
# VS Code Extension Version: 1.5.1 # 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: |
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 '"')
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"
echo Done
chromedriver -v

@ -1,4 +1,4 @@
#!/usr/bin/env sh #!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh" . "$(dirname -- "$0")/_/husky.sh"
yarn lint-staged

@ -1,3 +0,0 @@
{
"*.{tsx,ts,js,jsx,mjs,cjs}": ["prettier --write","eslint --fix"]
}

@ -3,12 +3,5 @@
"useTabs": false, "useTabs": false,
"printWidth": 180, "printWidth": 180,
"semi": false, "semi": false,
"singleQuote": true, "singleQuote": true
"quoteProps": "consistent",
"jsxSingleQuote": false,
"bracketSpacing": false,
"trailingComma": "none",
"jsxBracketSameLine": false,
"arrowParens": "always",
"singleAttributePerLine": false
} }

@ -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) [![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) [![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) ![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) [![Twitter Follow](https://img.shields.io/twitter/follow/ethereumremix?style=flat&logo=twitter&color=green)](https://twitter.com/ethereumremix)
</div> </div>
@ -282,7 +282,9 @@ parameters:
## Important Links ## Important Links
- Official website: https://remix-project.org
- Official documentation: https://remix-ide.readthedocs.io/en/latest/ - 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 - Medium: https://medium.com/remix-ide
- Twitter: https://twitter.com/ethereumremix - Twitter: https://twitter.com/ethereumremix
- Join Discord: https://discord.gg/q4vS2GVn

@ -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": []
}

@ -0,0 +1,17 @@
import React, { useEffect } from 'react'
import { CircomPluginClient } from './services/circomPluginClient'
function App() {
useEffect(() => {
new CircomPluginClient()
}, [])
return (
<div className="App">
</div>
)
}
export default App

@ -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<void> {
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<Record<string, string>> {
// 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
}
}

@ -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();

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Circuit - Compiler</title>
<base href="./" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous"/>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div id="root"></div>
</body>
</html>

@ -0,0 +1,8 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './app/app'
ReactDOM.render(
<App />,
document.getElementById('root')
)

@ -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';

@ -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": "sidePanel",
"documentation": "",
"repo": "https://github.com/ethereum/remix-project/tree/master/apps/circuit-compiler",
"maintainedBy": "Remix",
"authorContact": ""
}

@ -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"]
}

@ -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"
}
]
}

@ -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;
});

@ -1,36 +1,38 @@
export const scanAPIurls = { export const scanAPIurls = {
// all mainnet // all mainnet
1: "https://api.etherscan.io/api", 1: 'https://api.etherscan.io/api',
56: "https://api.bscscan.com/api", 56: 'https://api.bscscan.com/api',
137: "https://api.polygonscan.com/api", 137: 'https://api.polygonscan.com/api',
250: "https://api.ftmscan.com/api", 250: 'https://api.ftmscan.com/api',
42161: "https://api.arbiscan.io/api", 42161: 'https://api.arbiscan.io/api',
43114: "https://api.snowtrace.io/api", 43114: 'https://api.snowtrace.io/api',
1285: "https://api-moonriver.moonscan.io/api", 1285: 'https://api-moonriver.moonscan.io/api',
1284: "https://api-moonbeam.moonscan.io/api", 1284: 'https://api-moonbeam.moonscan.io/api',
25: "https://api.cronoscan.com/api", 25: 'https://api.cronoscan.com/api',
199: "https://api.bttcscan.com/api", 199: 'https://api.bttcscan.com/api',
10: "https://api-optimistic.etherscan.io/api", 10: 'https://api-optimistic.etherscan.io/api',
42220: "https://api.celoscan.io/api", 42220: 'https://api.celoscan.io/api',
288: "https://api.bobascan.com/api", 288: 'https://api.bobascan.com/api',
100: "https://api.gnosisscan.io/api", 100: 'https://api.gnosisscan.io/api',
1101: "https://api-zkevm.polygonscan.com/api", 1101: 'https://api-zkevm.polygonscan.com/api',
59144: 'https://api.lineascan.build/api',
// all testnet // all testnet
5: "https://api-goerli.etherscan.io/api", 5: 'https://api-goerli.etherscan.io/api',
11155111: "https://api-sepolia.etherscan.io/api", 11155111: 'https://api-sepolia.etherscan.io/api',
97: "https://api-testnet.bscscan.com/api", 97: 'https://api-testnet.bscscan.com/api',
80001: "https://api-testnet.polygonscan.com/api", 80001: 'https://api-testnet.polygonscan.com/api',
4002: "https://api-testnet.ftmscan.com/api", 4002: 'https://api-testnet.ftmscan.com/api',
421611: "https://api-testnet.arbiscan.io/api", 421611: 'https://api-testnet.arbiscan.io/api',
42170: "https://api-nova.arbiscan.io/api", 42170: 'https://api-nova.arbiscan.io/api',
43113: "https://api-testnet.snowtrace.io/api", 43113: 'https://api-testnet.snowtrace.io/api',
1287: "https://api-moonbase.moonscan.io/api", 1287: 'https://api-moonbase.moonscan.io/api',
338: "https://api-testnet.cronoscan.com/api", 338: 'https://api-testnet.cronoscan.com/api',
1028: "https://api-testnet.bttcscan.com/api", 1028: 'https://api-testnet.bttcscan.com/api',
420: "https://api-goerli-optimistic.etherscan.io/api", 420: 'https://api-goerli-optimistic.etherscan.io/api',
44787: "https://api-alfajores.celoscan.io/api", 44787: 'https://api-alfajores.celoscan.io/api',
2888: "https://api-testnet.bobascan.com/api", 2888: 'https://api-testnet.bobascan.com/api',
84531: "https://api-goerli.basescan.org/api", 84531: 'https://api-goerli.basescan.org/api',
1442: "https://api-testnet-zkevm.polygonscan.com/api" 1442: 'https://api-testnet-zkevm.polygonscan.com/api',
59140: 'https://api-testnet.lineascan.build/api',
} }

@ -2,8 +2,8 @@ import EventEmitter from 'events'
import {NightwatchBrowser} from 'nightwatch' import {NightwatchBrowser} from 'nightwatch'
class checkAnnotations extends EventEmitter { class checkAnnotations extends EventEmitter {
command (this: NightwatchBrowser, type: string, line: number): NightwatchBrowser { command(this: NightwatchBrowser, type: string): NightwatchBrowser {
this.api.assert.containsText(`.margin-view-overlays .${type} + div`, line.toString()).perform(() => this.emit('complete')) this.api.waitForElementPresent(`.glyph-margin-widgets .${type}`).perform(() => this.emit('complete'))
return this return this
} }
} }

@ -3,7 +3,7 @@ import { NightwatchBrowser } from 'nightwatch'
class checkAnnotationsNotPresent extends EventEmitter { class checkAnnotationsNotPresent extends EventEmitter {
command(this: NightwatchBrowser, type: string): NightwatchBrowser { command(this: NightwatchBrowser, type: string): NightwatchBrowser {
this.api.waitForElementNotPresent(`.margin-view-overlays .${type}`).perform(() => this.emit('complete')) this.api.waitForElementNotPresent(`.glyph-margin-widgets .${type}`).perform(() => this.emit('complete'))
return this return this
} }
} }

@ -5,12 +5,13 @@ import init from '../helpers/init'
module.exports = { module.exports = {
'@disabled': true, '@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) { 'before': function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done, 'http://127.0.0.1:8080', true) init(browser, done, 'http://127.0.0.1:8080', true)
}, },
'Should zoom in editor #group1': function (browser: NightwatchBrowser) { 'Should zoom in editor #group1': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('div[data-id="mainPanelPluginsContainer"]') browser
.waitForElementVisible('div[data-id="mainPanelPluginsContainer"]')
.clickLaunchIcon('filePanel') .clickLaunchIcon('filePanel')
.waitForElementVisible('div[data-id="filePanelFileExplorerTree"]') .waitForElementVisible('div[data-id="filePanelFileExplorerTree"]')
.openFile('contracts') .openFile('contracts')
@ -23,7 +24,8 @@ module.exports = {
}, },
'Should zoom out editor #group1': function (browser: NightwatchBrowser) { 'Should zoom out editor #group1': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('#editorView') browser
.waitForElementVisible('#editorView')
.checkElementStyle('.view-lines', 'font-size', '16px') .checkElementStyle('.view-lines', 'font-size', '16px')
.click('*[data-id="tabProxyZoomOut"]') .click('*[data-id="tabProxyZoomOut"]')
.click('*[data-id="tabProxyZoomOut"]') .click('*[data-id="tabProxyZoomOut"]')
@ -31,19 +33,23 @@ module.exports = {
}, },
'Should display compile error in editor #group1': function (browser: NightwatchBrowser) { 'Should display compile error in editor #group1': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('#editorView') browser
.waitForElementVisible('#editorView')
.setEditorValue(storageContractWithError + 'error') .setEditorValue(storageContractWithError + 'error')
.pause(2000) .pause(2000)
.waitForElementVisible('.margin-view-overlays .fa-exclamation-square', 120000) .waitForElementVisible('.glyph-margin-widgets .fa-exclamation-square', 120000)
.checkAnnotations('fa-exclamation-square', 29) // error .checkAnnotations('fa-exclamation-square') // error
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.checkAnnotationsNotPresent('fa-exclamation-square') // error .checkAnnotationsNotPresent('fa-exclamation-square') // error
.clickLaunchIcon('solidity') .clickLaunchIcon('solidity')
.checkAnnotations('fa-exclamation-square', 29) // error .checkAnnotations('fa-exclamation-square') // error
}, },
'Should minimize and maximize codeblock in editor #group1': '' + function (browser: NightwatchBrowser) { 'Should minimize and maximize codeblock in editor #group1':
browser.waitForElementVisible('#editorView') '' +
function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('#editorView')
.waitForElementVisible('.ace_open') .waitForElementVisible('.ace_open')
.click('.ace_start:nth-of-type(1)') .click('.ace_start:nth-of-type(1)')
.waitForElementVisible('.ace_closed') .waitForElementVisible('.ace_closed')
@ -52,24 +58,35 @@ module.exports = {
}, },
'Should add breakpoint to editor #group1': function (browser: NightwatchBrowser) { 'Should add breakpoint to editor #group1': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('#editorView') browser
.waitForElementNotPresent('.margin-view-overlays .fa-circle') .waitForElementVisible('#editorView')
.execute(() => { .waitForElementNotPresent('.glyph-margin-widgets .fa-circle')
(window as any).addRemixBreakpoint(1) .execute(
}, [], () => {}) () => {
.waitForElementVisible('.margin-view-overlays .fa-circle') ;(window as any).addRemixBreakpoint(1)
},
[],
() => {}
)
.waitForElementVisible('.glyph-margin-widgets .fa-circle')
}, },
'Should load syntax highlighter for ace light theme #group1': '' + function (browser: NightwatchBrowser) { 'Should load syntax highlighter for ace light theme #group1':
browser.waitForElementVisible('#editorView') '' +
function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('#editorView')
.checkElementStyle('.ace_keyword', 'color', aceThemes.light.keyword) .checkElementStyle('.ace_keyword', 'color', aceThemes.light.keyword)
.checkElementStyle('.ace_comment.ace_doc', 'color', aceThemes.light.comment) .checkElementStyle('.ace_comment.ace_doc', 'color', aceThemes.light.comment)
.checkElementStyle('.ace_function', 'color', aceThemes.light.function) .checkElementStyle('.ace_function', 'color', aceThemes.light.function)
.checkElementStyle('.ace_variable', 'color', aceThemes.light.variable) .checkElementStyle('.ace_variable', 'color', aceThemes.light.variable)
}, },
'Should load syntax highlighter for ace dark theme #group1': '' + function (browser: NightwatchBrowser) { 'Should load syntax highlighter for ace dark theme #group1':
browser.waitForElementVisible('*[data-id="verticalIconsKindsettings"]') '' +
function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="verticalIconsKindsettings"]')
.click('*[data-id="verticalIconsKindsettings"]') .click('*[data-id="verticalIconsKindsettings"]')
.waitForElementVisible('*[data-id="settingsTabThemeLabelDark"]') .waitForElementVisible('*[data-id="settingsTabThemeLabelDark"]')
.click('*[data-id="settingsTabThemeLabelDark"]') .click('*[data-id="settingsTabThemeLabelDark"]')
@ -101,8 +118,11 @@ module.exports = {
.checkElementStyle('.highlightLine51', '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) { 'Should remove 1 highlight from source code #group1':
browser.waitForElementVisible('li[data-id="treeViewLitreeViewItemremoveSourcehighlightScript.js"]') '' +
function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('li[data-id="treeViewLitreeViewItemremoveSourcehighlightScript.js"]')
.click('li[data-id="treeViewLitreeViewItemremoveSourcehighlightScript.js"]') .click('li[data-id="treeViewLitreeViewItemremoveSourcehighlightScript.js"]')
.pause(2000) .pause(2000)
.executeScriptInTerminal('remix.exeCurrent()') .executeScriptInTerminal('remix.exeCurrent()')
@ -116,7 +136,8 @@ module.exports = {
}, },
'Should remove all highlights from source code #group1': function (browser: NightwatchBrowser) { '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"]') .click('li[data-id="treeViewLitreeViewItemremoveAllSourcehighlightScript.js"]')
.pause(2000) .pause(2000)
.executeScriptInTerminal('remix.exeCurrent()') .executeScriptInTerminal('remix.exeCurrent()')
@ -126,8 +147,7 @@ module.exports = {
.waitForElementNotPresent('.highlightLine33', 60000) .waitForElementNotPresent('.highlightLine33', 60000)
.waitForElementNotPresent('.highlightLine41', 60000) .waitForElementNotPresent('.highlightLine41', 60000)
.waitForElementNotPresent('.highlightLine51', 60000) .waitForElementNotPresent('.highlightLine51', 60000)
}, }
} }
const aceThemes = { const aceThemes = {
@ -233,5 +253,3 @@ contract Storage {
return number; return number;
} }
}` }`

@ -17,7 +17,6 @@ module.exports = {
before: function (browser: NightwatchBrowser, done: VoidFunction) { before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done, 'http://127.0.0.1:8080', false) init(browser, done, 'http://127.0.0.1:8080', false)
}, },
'Should load the test file': function (browser: NightwatchBrowser) { 'Should load the test file': function (browser: NightwatchBrowser) {
browser.openFile('contracts') browser.openFile('contracts')
.openFile('contracts/3_Ballot.sol') .openFile('contracts/3_Ballot.sol')
@ -86,7 +85,47 @@ module.exports = {
const path = "//*[@class='view-line' and contains(.,'Voter') and contains(.,'struct')]//span//span[contains(.,'Voter')]" const path = "//*[@class='view-line' and contains(.,'Voter') and contains(.,'struct')]//span//span[contains(.,'Voter')]"
const expectedContent = 'StructDefinition' const expectedContent = 'StructDefinition'
checkEditorHoverContent(browser, path, expectedContent) checkEditorHoverContent(browser, path, expectedContent)
} },
'Add token file': function (browser: NightwatchBrowser) {
browser.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, 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, IERC20Metadata, IERC20, Context'
checkEditorHoverContent(browser, path, expectedContent, 25)
},
} }
@ -234,3 +273,37 @@ contract BallotHoverTest {
} }
} }
` `
const myToken = `
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC20, ERC20Burnable, Pausable, Ownable {
constructor() ERC20("MyToken", "MTK") {}
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
function _beforeTokenTransfer(address from, address to, uint256 amount)
internal
whenNotPaused
override
{
super._beforeTokenTransfer(from, to, amount);
}
}
`

@ -3,25 +3,25 @@ import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init' import init from '../helpers/init'
const openReferences = (browser: NightwatchBrowser, path: string) => { const openReferences = (browser: NightwatchBrowser, path: string) => {
(browser as any).useXpath() ;(browser as any)
.useXpath()
.useXpath() .useXpath()
.waitForElementVisible(path) .waitForElementVisible(path)
.click(path) .click(path)
.perform(function () { .perform(function () {
const actions = this.actions({ async: true }); const actions = this.actions({async: true})
return actions. return actions.keyDown(this.Keys.SHIFT).sendKeys(this.Keys.F12)
keyDown(this.Keys.SHIFT).
sendKeys(this.Keys.F12)
}) })
} }
module.exports = { module.exports = {
before: function (browser: NightwatchBrowser, done: VoidFunction) { 'before': function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done, 'http://127.0.0.1:8080', false) init(browser, done, 'http://127.0.0.1:8080', false)
}, },
'Should load the test file': function (browser: NightwatchBrowser) { 'Should load the test file': function (browser: NightwatchBrowser) {
browser.openFile('contracts') browser
.openFile('contracts')
.openFile('contracts/3_Ballot.sol') .openFile('contracts/3_Ballot.sol')
.waitForElementVisible('#editorView') .waitForElementVisible('#editorView')
.setEditorValue(BallotWithARefToOwner) .setEditorValue(BallotWithARefToOwner)
@ -32,19 +32,21 @@ module.exports = {
browser.scrollToLine(48) browser.scrollToLine(48)
const path = "//*[@class='view-line' and contains(.,'length') and contains(.,'proposalNames')]//span//span[contains(.,'proposalNames')]" const path = "//*[@class='view-line' and contains(.,'length') and contains(.,'proposalNames')]//span//span[contains(.,'proposalNames')]"
openReferences(browser, path) openReferences(browser, path)
browser.waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch']//span[contains(.,'length; i++')]") browser
.waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch']//span[contains(.,'name:')]") .waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch'][contains(.,'length; i++')]")
.waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch']//span[contains(.,'constructor')]") .waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch'][contains(.,'name:')]")
.waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch'][contains(.,'constructor')]")
.keys(browser.Keys.ESCAPE) .keys(browser.Keys.ESCAPE)
}, },
'Should show references of getOwner': function (browser: NightwatchBrowser) { 'Should show references of getOwner': function (browser: NightwatchBrowser) {
browser.scrollToLine(39) browser.scrollToLine(39)
const path = "//*[@class='view-line' and contains(.,'getOwner') and contains(.,'cowner')]//span//span[contains(.,'getOwner')]" const path = "//*[@class='view-line' and contains(.,'getOwner') and contains(.,'cowner')]//span//span[contains(.,'getOwner')]"
openReferences(browser, path) openReferences(browser, path)
browser.useXpath() browser
.waitForElementVisible("//*[@class='monaco-highlighted-label']//span[contains(.,'2_Owner.sol')]") .useXpath()
.waitForElementVisible("//*[@class='monaco-highlighted-label']//span[contains(.,'3_Ballot.sol')]") .waitForElementVisible("//*[@class='monaco-highlighted-label'][contains(.,'2_Owner.sol')]")
.waitForElementVisible("//*[@class='monaco-highlighted-label referenceMatch']//span[contains(.,'cowner.getOwner')]") .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)')]") .waitForElementVisible("//*[contains(@class, 'results-loaded') and contains(., 'References (2)')]")
.keys(browser.Keys.ESCAPE) .keys(browser.Keys.ESCAPE)
} }

@ -238,8 +238,8 @@ module.exports = {
}) })
.addFile('tests/hhLogs_test.sol', sources[0]['tests/hhLogs_test.sol']) .addFile('tests/hhLogs_test.sol', sources[0]['tests/hhLogs_test.sol'])
.clickLaunchIcon('solidityUnitTesting') .clickLaunchIcon('solidityUnitTesting')
.waitForElementVisible('*[id="singleTesttests/Ballot_test.sol"]', 60000) .waitForElementVisible('*[id="idsingleTesttests/Ballot_test.sol"]', 60000)
.click('*[id="singleTesttests/Ballot_test.sol"]') .click('*[id="idsingleTesttests/Ballot_test.sol"]')
.click('#runTestsTabRunAction') .click('#runTestsTabRunAction')
.pause(2000) .pause(2000)
.waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000) .waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000)
@ -261,8 +261,8 @@ module.exports = {
.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]') .waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.addFile('tests/ballotFailedLog_test.sol', sources[0]['tests/ballotFailedLog_test.sol']) .addFile('tests/ballotFailedLog_test.sol', sources[0]['tests/ballotFailedLog_test.sol'])
.clickLaunchIcon('solidityUnitTesting') .clickLaunchIcon('solidityUnitTesting')
.waitForElementVisible('*[id="singleTesttests/Ballot_test.sol"]', 60000) .waitForElementVisible('*[id="idsingleTesttests/Ballot_test.sol"]', 60000)
.click('*[id="singleTesttests/Ballot_test.sol"]') .click('*[id="idsingleTesttests/Ballot_test.sol"]')
.click('#runTestsTabRunAction') .click('#runTestsTabRunAction')
.pause(2000) .pause(2000)
.waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000) .waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000)
@ -278,8 +278,8 @@ module.exports = {
.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]') .waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.addFile('tests/ballotFailedDebug_test.sol', sources[0]['tests/ballotFailedDebug_test.sol']) .addFile('tests/ballotFailedDebug_test.sol', sources[0]['tests/ballotFailedDebug_test.sol'])
.clickLaunchIcon('solidityUnitTesting') .clickLaunchIcon('solidityUnitTesting')
.waitForElementVisible('*[id="singleTesttests/Ballot_test.sol"]', 60000) .waitForElementVisible('*[id="idsingleTesttests/Ballot_test.sol"]', 60000)
.click('*[id="singleTesttests/Ballot_test.sol"]') .click('*[id="idsingleTesttests/Ballot_test.sol"]')
.click('#runTestsTabRunAction') .click('#runTestsTabRunAction')
.waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000) .waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000)
.waitForElementContainsText('#solidityUnittestsOutput', 'tests/ballotFailedDebug_test.sol', 60000) .waitForElementContainsText('#solidityUnittestsOutput', 'tests/ballotFailedDebug_test.sol', 60000)

@ -1,62 +1,62 @@
// Merge custom command types with nightwatch types // Merge custom command types with nightwatch types
/* eslint-disable no-use-before-define */ /* eslint-disable no-use-before-define */
import {NightwatchBrowser} from 'nightwatch' // eslint-disable-line @typescript-eslint/no-unused-vars import {NightwatchBrowser} from 'nightwatch' // eslint-disable-line @typescript-eslint/no-unused-vars
export type callbackCheckVerifyCallReturnValue = (values: string[]) => { message: string, pass: boolean } export type callbackCheckVerifyCallReturnValue = (values: string[]) => {message: string; pass: boolean}
declare module 'nightwatch' { declare module 'nightwatch' {
export interface NightwatchCustomCommands { export interface NightwatchCustomCommands {
clickLaunchIcon(icon: string): NightwatchBrowser, clickLaunchIcon(icon: string): NightwatchBrowser
switchBrowserTab(index: number): NightwatchBrowser, switchBrowserTab(index: number): NightwatchBrowser
scrollAndClick(target: string): NightwatchBrowser, scrollAndClick(target: string): NightwatchBrowser
scrollInto(target: string): NightwatchBrowser, scrollInto(target: string): NightwatchBrowser
testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser, testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser
setEditorValue(value: string, callback?: () => void): NightwatchBrowser, setEditorValue(value: string, callback?: () => void): NightwatchBrowser
addFile(name: string, content: NightwatchContractContent): NightwatchBrowser, addFile(name: string, content: NightwatchContractContent): NightwatchBrowser
verifyContracts(compiledContractNames: string[], opts?: { wait: number, version?: string, runs?: string }): NightwatchBrowser, verifyContracts(compiledContractNames: string[], opts?: {wait: number; version?: string; runs?: string}): NightwatchBrowser
selectAccount(account?: string): NightwatchBrowser, selectAccount(account?: string): NightwatchBrowser
clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser, clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser
testFunction(txHash: string, expectedInput: NightwatchTestFunctionExpectedInput): NightwatchBrowser, testFunction(txHash: string, expectedInput: NightwatchTestFunctionExpectedInput): NightwatchBrowser
goToVMTraceStep(step: number, incr?: number): NightwatchBrowser, goToVMTraceStep(step: number, incr?: number): NightwatchBrowser
checkVariableDebug(id: string, debugValue: NightwatchCheckVariableDebugValue): NightwatchBrowser, checkVariableDebug(id: string, debugValue: NightwatchCheckVariableDebugValue): NightwatchBrowser
addAtAddressInstance(address: string, isValidFormat: boolean, isValidChecksum: boolean, isAbi?: boolean): NightwatchBrowser, addAtAddressInstance(address: string, isValidFormat: boolean, isValidChecksum: boolean, isAbi?: boolean): NightwatchBrowser
modalFooterOKClick(id?: string): NightwatchBrowser, modalFooterOKClick(id?: string): NightwatchBrowser
clickInstance(index: number): NightwatchBrowser, clickInstance(index: number): NightwatchBrowser
journalLastChildIncludes(val: string): NightwatchBrowser, journalLastChildIncludes(val: string): NightwatchBrowser
executeScriptInTerminal(script: string): NightwatchBrowser, executeScriptInTerminal(script: string): NightwatchBrowser
clearEditableContent(cssSelector: string): NightwatchBrowser, clearEditableContent(cssSelector: string): NightwatchBrowser
journalChildIncludes(val: string, opts = { shouldHaveOnlyOneOccurence: boolean }): NightwatchBrowser, journalChildIncludes(val: string, opts = {shouldHaveOnlyOneOccurence: boolean}): NightwatchBrowser
debugTransaction(index: number): NightwatchBrowser, debugTransaction(index: number): NightwatchBrowser
checkElementStyle(cssSelector: string, styleProperty: string, expectedResult: string): NightwatchBrowser, checkElementStyle(cssSelector: string, styleProperty: string, expectedResult: string): NightwatchBrowser
openFile(name: string): NightwatchBrowser, openFile(name: string): NightwatchBrowser
refreshPage(): NightwatchBrowser, refreshPage(): NightwatchBrowser
verifyLoad(): NightwatchBrowser, verifyLoad(): NightwatchBrowser
renamePath(path: string, newFileName: string, renamedPath: string): NightwatchBrowser, renamePath(path: string, newFileName: string, renamedPath: string): NightwatchBrowser
rightClickCustom(cssSelector: string): NightwatchBrowser, rightClickCustom(cssSelector: string): NightwatchBrowser
scrollToLine(line: number): NightwatchBrowser, scrollToLine(line: number): NightwatchBrowser
waitForElementContainsText(id: string, value: string, timeout?: number): NightwatchBrowser, waitForElementContainsText(id: string, value: string, timeout?: number): NightwatchBrowser
getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser, getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser
modalFooterCancelClick(id?: string): NightwatchBrowser, modalFooterCancelClick(id?: string): NightwatchBrowser
selectContract(contractName: string): NightwatchBrowser, selectContract(contractName: string): NightwatchBrowser
createContract(inputParams: string): NightwatchBrowser, createContract(inputParams: string): NightwatchBrowser
getAddressAtPosition(index: number, cb: (pos: string) => void): NightwatchBrowser, getAddressAtPosition(index: number, cb: (pos: string) => void): NightwatchBrowser
testConstantFunction(address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser, testConstantFunction(address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser
getEditorValue(callback: (content: string) => void): NightwatchBrowser, getEditorValue(callback: (content: string) => void): NightwatchBrowser
getInstalledPlugins(cb: (plugins: string[]) => void): NightwatchBrowser, getInstalledPlugins(cb: (plugins: string[]) => void): NightwatchBrowser
verifyCallReturnValue(address: string, checks: string[] | callbackCheckVerifyCallReturnValue): NightwatchBrowser, verifyCallReturnValue(address: string, checks: string[] | callbackCheckVerifyCallReturnValue): NightwatchBrowser
testEditorValue(testvalue: string): NightwatchBrowser, testEditorValue(testvalue: string): NightwatchBrowser
removeFile(path: string, workspace: string): NightwatchBrowser, removeFile(path: string, workspace: string): NightwatchBrowser
switchBrowserWindow(url: string, windowName: string, cb: (browser: NightwatchBrowser, window?: NightwatchCallbackResult<Window>) => void): NightwatchBrowser, switchBrowserWindow(url: string, windowName: string, cb: (browser: NightwatchBrowser, window?: NightwatchCallbackResult<Window>) => void): NightwatchBrowser
setupMetamask(passphrase: string, password: string): NightwatchBrowser, setupMetamask(passphrase: string, password: string): NightwatchBrowser
signMessage(msg: string, callback: (hash: { value: string }, signature: { value: string }) => void): NightwatchBrowser, signMessage(msg: string, callback: (hash: {value: string}, signature: {value: string}) => void): NightwatchBrowser
setSolidityCompilerVersion(version: string): NightwatchBrowser, setSolidityCompilerVersion(version: string): NightwatchBrowser
clickElementAtPosition(cssSelector: string, index: number, opt?: { forceSelectIfUnselected: boolean }): NightwatchBrowser, clickElementAtPosition(cssSelector: string, index: number, opt?: {forceSelectIfUnselected: boolean}): NightwatchBrowser
notContainsText(cssSelector: string, text: string): NightwatchBrowser, notContainsText(cssSelector: string, text: string): NightwatchBrowser
sendLowLevelTx(address: string, value: string, callData: string): NightwatchBrowser, sendLowLevelTx(address: string, value: string, callData: string): NightwatchBrowser
journalLastChild(val: string): NightwatchBrowser, journalLastChild(val: string): NightwatchBrowser
checkTerminalFilter(filter: string, test: string): NightwatchBrowser, checkTerminalFilter(filter: string, test: string): NightwatchBrowser
noWorkerErrorFor(version: string): NightwatchBrowser, noWorkerErrorFor(version: string): NightwatchBrowser
validateValueInput(selector: string, valueTosSet: string, expectedValue: string): NightwatchBrowser validateValueInput(selector: string, valueTosSet: string, expectedValue: string): NightwatchBrowser
checkAnnotations(type: string, line: number): NightwatchBrowser checkAnnotations(type: string): NightwatchBrowser
checkAnnotationsNotPresent(type: string): NightwatchBrowser checkAnnotationsNotPresent(type: string): NightwatchBrowser
getLastTransactionHash(callback: (hash: string) => void) getLastTransactionHash(callback: (hash: string) => void)
currentWorkspaceIs(name: string): NightwatchBrowser currentWorkspaceIs(name: string): NightwatchBrowser
@ -65,17 +65,17 @@ declare module 'nightwatch' {
clearConsole(this: NightwatchBrowser): NightwatchBrowser clearConsole(this: NightwatchBrowser): NightwatchBrowser
clearTransactions(this: NightwatchBrowser): NightwatchBrowser clearTransactions(this: NightwatchBrowser): NightwatchBrowser
getBrowserLogs(this: NightwatchBrowser): NightwatchBrowser getBrowserLogs(this: NightwatchBrowser): NightwatchBrowser
currentSelectedFileIs (name: string): NightwatchBrowser, currentSelectedFileIs(name: string): NightwatchBrowser
switchWorkspace: (workspaceName: string) => NightwatchBrowser switchWorkspace: (workspaceName: string) => NightwatchBrowser
switchEnvironment: (provider: string) => NightwatchBrowser switchEnvironment: (provider: string) => NightwatchBrowser
connectToExternalHttpProvider: (url: string, identifier: string) => NightwatchBrowser connectToExternalHttpProvider: (url: string, identifier: string) => NightwatchBrowser
} }
export interface NightwatchBrowser { export interface NightwatchBrowser {
api: this, api: this
emit: (status: string) => void, emit: (status: string) => void
fullscreenWindow: (result?: any) => this, fullscreenWindow: (result?: any) => this
keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void): NightwatchBrowser, keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void): NightwatchBrowser
sendKeys: (selector: string, inputValue: string | string[], callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void) => NightwatchBrowser sendKeys: (selector: string, inputValue: string | string[], callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void) => NightwatchBrowser
} }
@ -84,11 +84,11 @@ declare module 'nightwatch' {
} }
export interface NightwatchContractContent { export interface NightwatchContractContent {
content: string; content: string
} }
export interface NightwatchClickFunctionExpectedInput { export interface NightwatchClickFunctionExpectedInput {
types: string, types: string
values: string values: string
} }
@ -97,7 +97,7 @@ declare module 'nightwatch' {
} }
export interface NightwatchTestConstantFunctionExpectedInput { export interface NightwatchTestConstantFunctionExpectedInput {
types: string, types: string
values: string values: string
} }

@ -3,7 +3,7 @@
"$schema": "../../node_modules/nx/schemas/project-schema.json", "$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/remix-ide/src", "sourceRoot": "apps/remix-ide/src",
"projectType": "application", "projectType": "application",
"implicitDependencies": ["doc-gen", "doc-viewer", "etherscan", "vyper", "solhint", "walletconnect"], "implicitDependencies": ["doc-gen", "doc-viewer", "etherscan", "vyper", "solhint", "walletconnect", "circuit-compiler"],
"targets": { "targets": {
"build": { "build": {
"executor": "@nrwl/webpack:webpack", "executor": "@nrwl/webpack:webpack",

@ -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 reset --hard -master-commit-hash-
- git push -f origin remix_live - 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 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

@ -41,10 +41,13 @@ import { InjectedProviderDefault } from './app/providers/injected-provider-defau
import {InjectedProviderTrustWallet} from './app/providers/injected-provider-trustwallet' import {InjectedProviderTrustWallet} from './app/providers/injected-provider-trustwallet'
import {Injected0ptimismProvider} from './app/providers/injected-optimism-provider' import {Injected0ptimismProvider} from './app/providers/injected-optimism-provider'
import {InjectedArbitrumOneProvider} from './app/providers/injected-arbitrum-one-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 {FileDecorator} from './app/plugins/file-decorator'
import {CodeFormat} from './app/plugins/code-format' import {CodeFormat} from './app/plugins/code-format'
import {SolidityUmlGen} from './app/plugins/solidity-umlgen' import {SolidityUmlGen} from './app/plugins/solidity-umlgen'
import {ContractFlattener} from './app/plugins/contractFlattener' import {ContractFlattener} from './app/plugins/contractFlattener'
import {OpenAIGpt} from './app/plugins/openaigpt'
const isElectron = require('is-electron') const isElectron = require('is-electron')
@ -93,9 +96,7 @@ class AppComponent {
api: this._components.filesProviders.browser, api: this._components.filesProviders.browser,
name: 'fileproviders/browser' name: 'fileproviders/browser'
}) })
this._components.filesProviders.localhost = new RemixDProvider( this._components.filesProviders.localhost = new RemixDProvider(this.appManager)
this.appManager
)
Registry.getInstance().put({ Registry.getInstance().put({
api: this._components.filesProviders.localhost, api: this._components.filesProviders.localhost,
name: 'fileproviders/localhost' name: 'fileproviders/localhost'
@ -119,7 +120,7 @@ class AppComponent {
this.panels = {} this.panels = {}
this.workspace = pluginLoader.get() this.workspace = pluginLoader.get()
this.engine = new RemixEngine() this.engine = new RemixEngine()
this.engine.register(appManager); this.engine.register(appManager)
const matomoDomains = { const matomoDomains = {
'remix-alpha.ethereum.org': 27, 'remix-alpha.ethereum.org': 27,
@ -127,15 +128,8 @@ class AppComponent {
'remix.ethereum.org': 23, 'remix.ethereum.org': 23,
'6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod': 35 // remix desktop '6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod': 35 // remix desktop
} }
this.showMatamo = this.showMatamo = matomoDomains[window.location.hostname] && !Registry.getInstance().get('config').api.exists('settings/matomo-analytics')
matomoDomains[window.location.hostname] && this.walkthroughService = new WalkthroughService(appManager, this.showMatamo)
!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'] const hosts = ['127.0.0.1:8080', '192.168.0.101:8080', 'localhost:8080']
// workaround for Electron support // workaround for Electron support
@ -159,9 +153,10 @@ class AppComponent {
// ----------------- editor service ---------------------------- // ----------------- editor service ----------------------------
const editor = new Editor() // wrapper around ace editor const editor = new Editor() // wrapper around ace editor
Registry.getInstance().put({api: editor, name: 'editor'}) Registry.getInstance().put({api: editor, name: 'editor'})
editor.event.register('requiringToSaveCurrentfile', () => editor.event.register('requiringToSaveCurrentfile', (currentFile) => {
fileManager.saveCurrentFile() fileManager.saveCurrentFile()
) if (currentFile.endsWith('.circom')) this.appManager.activatePlugin(['circuit-compiler'])
})
// ----------------- fileManager service ---------------------------- // ----------------- fileManager service ----------------------------
const fileManager = new FileManager(editor, appManager) const fileManager = new FileManager(editor, appManager)
@ -187,6 +182,9 @@ class AppComponent {
// ----------------- ContractFlattener ---------------------------- // ----------------- ContractFlattener ----------------------------
const contractFlattener = new ContractFlattener() const contractFlattener = new ContractFlattener()
// ----------------- Open AI --------------------------------------
const openaigpt = new OpenAIGpt()
// ----------------- import content service ------------------------ // ----------------- import content service ------------------------
const contentImport = new CompilerImports() const contentImport = new CompilerImports()
@ -220,9 +218,11 @@ class AppComponent {
const foundryProvider = new FoundryProvider(blockchain) const foundryProvider = new FoundryProvider(blockchain)
const externalHttpProvider = new ExternalHttpProvider(blockchain) const externalHttpProvider = new ExternalHttpProvider(blockchain)
const trustWalletInjectedProvider = new InjectedProviderTrustWallet() const trustWalletInjectedProvider = new InjectedProviderTrustWallet()
const defaultInjectedProvider = new InjectedProviderDefault const defaultInjectedProvider = new InjectedProviderDefault()
const injected0ptimismProvider = new Injected0ptimismProvider() const injected0ptimismProvider = new Injected0ptimismProvider()
const injectedArbitrumOneProvider = new InjectedArbitrumOneProvider() const injectedArbitrumOneProvider = new InjectedArbitrumOneProvider()
const injectedEphemeryTestnetProvider = new InjectedEphemeryTestnetProvider()
const injectedSKALEChaosTestnetProvider = new InjectedSKALEChaosTestnetProvider()
// ----------------- convert offset to line/column service ----------- // ----------------- convert offset to line/column service -----------
const offsetToLineColumnConverter = new OffsetToLineColumnConverter() const offsetToLineColumnConverter = new OffsetToLineColumnConverter()
Registry.getInstance().put({ Registry.getInstance().put({
@ -232,11 +232,11 @@ class AppComponent {
// ----------------- run script after each compilation results ----------- // ----------------- run script after each compilation results -----------
const compileAndRun = new CompileAndRun() const compileAndRun = new CompileAndRun()
// -------------------Terminal---------------------------------------- // -------------------Terminal----------------------------------------
makeUdapp(blockchain, compilersArtefacts, domEl => terminal.logHtml(domEl)) makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl))
const terminal = new Terminal( const terminal = new Terminal(
{appManager, blockchain}, {appManager, blockchain},
{ {
getPosition: event => { getPosition: (event) => {
const limitUp = 36 const limitUp = 36
const limitDown = 20 const limitDown = 20
const height = window.innerHeight const height = window.innerHeight
@ -298,11 +298,14 @@ class AppComponent {
trustWalletInjectedProvider, trustWalletInjectedProvider,
injected0ptimismProvider, injected0ptimismProvider,
injectedArbitrumOneProvider, injectedArbitrumOneProvider,
injectedEphemeryTestnetProvider,
injectedSKALEChaosTestnetProvider,
this.walkthroughService, this.walkthroughService,
search, search,
solidityumlgen, solidityumlgen,
contractFlattener, contractFlattener,
solidityScript solidityScript,
openaigpt
]) ])
// LAYOUT & SYSTEM VIEWS // LAYOUT & SYSTEM VIEWS
@ -316,42 +319,18 @@ class AppComponent {
this.sidePanel = new SidePanel() this.sidePanel = new SidePanel()
this.hiddenPanel = new HiddenPanel() this.hiddenPanel = new HiddenPanel()
const pluginManagerComponent = new PluginManagerComponent( const pluginManagerComponent = new PluginManagerComponent(appManager, this.engine)
appManager,
this.engine
)
const filePanel = new FilePanel(appManager) const filePanel = new FilePanel(appManager)
const landingPage = new LandingPage( const landingPage = new LandingPage(appManager, this.menuicons, fileManager, filePanel, contentImport)
appManager, this.settings = new SettingsTab(Registry.getInstance().get('config').api, editor, appManager)
this.menuicons,
fileManager,
filePanel,
contentImport
)
this.settings = new SettingsTab(
Registry.getInstance().get('config').api,
editor,
appManager
)
this.engine.register([ this.engine.register([this.menuicons, landingPage, this.hiddenPanel, this.sidePanel, filePanel, pluginManagerComponent, this.settings])
this.menuicons,
landingPage,
this.hiddenPanel,
this.sidePanel,
filePanel,
pluginManagerComponent,
this.settings
])
// CONTENT VIEWS & DEFAULT PLUGINS // CONTENT VIEWS & DEFAULT PLUGINS
const openZeppelinProxy = new OpenZeppelinProxy(blockchain) const openZeppelinProxy = new OpenZeppelinProxy(blockchain)
const linkLibraries = new LinkLibraries(blockchain) const linkLibraries = new LinkLibraries(blockchain)
const deployLibraries = new DeployLibraries(blockchain) const deployLibraries = new DeployLibraries(blockchain)
const compileTab = new CompileTab( const compileTab = new CompileTab(Registry.getInstance().get('config').api, Registry.getInstance().get('filemanager').api)
Registry.getInstance().get('config').api,
Registry.getInstance().get('filemanager').api
)
const run = new RunTab( const run = new RunTab(
blockchain, blockchain,
Registry.getInstance().get('config').api, Registry.getInstance().get('config').api,
@ -410,27 +389,44 @@ class AppComponent {
await this.appManager.activatePlugin(['layout']) await this.appManager.activatePlugin(['layout'])
await this.appManager.activatePlugin(['notification']) await this.appManager.activatePlugin(['notification'])
await this.appManager.activatePlugin(['editor']) 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(['mainPanel', 'menuicons', 'tabs'])
await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately
await this.appManager.activatePlugin(['home']) await this.appManager.activatePlugin(['home'])
await this.appManager.activatePlugin(['settings', 'config']) 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(['settings'])
await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder']) await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder'])
await this.appManager.activatePlugin(['solidity-script']) await this.appManager.activatePlugin(['solidity-script', 'openaigpt'])
this.appManager.on( this.appManager.on('filePanel', 'workspaceInitializationCompleted', async () => {
'filePanel',
'workspaceInitializationCompleted',
async () => {
// for e2e tests // for e2e tests
const loadedElement = document.createElement('span') const loadedElement = document.createElement('span')
loadedElement.setAttribute('data-id', 'workspaceloaded') loadedElement.setAttribute('data-id', 'workspaceloaded')
document.body.appendChild(loadedElement) document.body.appendChild(loadedElement)
await this.appManager.registerContextMenuItems() await this.appManager.registerContextMenuItems()
} })
)
await this.appManager.activatePlugin(['filePanel']) await this.appManager.activatePlugin(['filePanel'])
// Set workspace after initial activation // Set workspace after initial activation
@ -441,9 +437,7 @@ class AppComponent {
.then(async () => { .then(async () => {
try { try {
if (params.deactivate) { if (params.deactivate) {
await this.appManager.deactivatePlugin( await this.appManager.deactivatePlugin(params.deactivate.split(','))
params.deactivate.split(',')
)
} }
} catch (e) { } catch (e) {
console.log(e) console.log(e)
@ -453,10 +447,7 @@ class AppComponent {
this.menuicons.select('solidity') this.menuicons.select('solidity')
} else { } else {
// If plugins are loaded from the URL params, we focus on the last one. // If plugins are loaded from the URL params, we focus on the last one.
if ( if (this.appManager.pluginLoader.current === 'queryParams' && this.workspace.length > 0) {
this.appManager.pluginLoader.current === 'queryParams' &&
this.workspace.length > 0
) {
this.menuicons.select(this.workspace[this.workspace.length - 1]) this.menuicons.select(this.workspace[this.workspace.length - 1])
} else { } else {
this.appManager.call('tabs', 'focus', 'home') this.appManager.call('tabs', 'focus', 'home')
@ -473,17 +464,13 @@ class AppComponent {
} }
if (params.calls) { if (params.calls) {
const calls = params.calls.split("///"); const calls = params.calls.split('///')
// call all functions in the list, one after the other // call all functions in the list, one after the other
for (const call of calls) { for (const call of calls) {
const callDetails = call.split("//"); const callDetails = call.split('//')
if (callDetails.length > 1) { if (callDetails.length > 1) {
this.appManager.call( this.appManager.call('notification', 'toast', `initiating ${callDetails[0]} and calling "${callDetails[1]}" ...`)
"notification",
"toast",
`initiating ${callDetails[0]} and calling "${callDetails[1]}" ...`
);
// @todo(remove the timeout when activatePlugin is on 0.3.0) // @todo(remove the timeout when activatePlugin is on 0.3.0)
try { try {

@ -13,7 +13,7 @@ const profile = {
name: 'editor', name: 'editor',
description: 'service - editor', description: 'service - editor',
version: packageJson.version, 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 { class Editor extends Plugin {
@ -175,8 +175,8 @@ class Editor extends Plugin {
} }
this.saveTimeout = window.setTimeout(() => { this.saveTimeout = window.setTimeout(() => {
this.triggerEvent('contentChanged', []) this.triggerEvent('contentChanged', [currentFile, input])
this.triggerEvent('requiringToSaveCurrentfile', []) this.triggerEvent('requiringToSaveCurrentfile', [currentFile])
}, 500) }, 500)
} }
@ -579,6 +579,10 @@ class Editor extends Plugin {
this.clearDecorationsByPlugin(session, from, 'lineTextPerFile', this.registeredDecorations, this.currentDecorations) this.clearDecorationsByPlugin(session, from, 'lineTextPerFile', this.registeredDecorations, this.currentDecorations)
} }
} }
getPositionAt(offset) {
return this.api.getPositionAt(offset)
}
} }
module.exports = Editor module.exports = Editor

@ -1,3 +1,4 @@
'use strict' 'use strict'
import { saveAs } from 'file-saver' import { saveAs } from 'file-saver'
import JSZip from 'jszip' import JSZip from 'jszip'
@ -21,7 +22,7 @@ const profile = {
icon: 'assets/img/fileManager.webp', icon: 'assets/img/fileManager.webp',
permission: true, permission: true,
version: packageJson.version, version: packageJson.version,
methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'writeMultipleFiles', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir',
'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh',
'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'saveCurrentFile', 'setBatchFiles', 'isGitRepo'], 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'saveCurrentFile', 'setBatchFiles', 'isGitRepo'],
kind: 'file-system' kind: 'file-system'
@ -217,6 +218,36 @@ 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, fileData, folderPath) {
try {
let alert = true
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._handleIsFile(path, `Cannot write file ${path}`)
await this.setMultipleFileContent(path, fileData[i], folderPath, alert)
} else {
await this.setMultipleFileContent(path, fileData[i], folderPath, alert)
this.emit('fileAdded', path)
}
alert = false
}
} catch (e) {
throw new Error(e)
}
}
/** /**
* Return the content of a specific file * Return the content of a specific file
* @param {string} path path of the file * @param {string} path path of the file
@ -572,13 +603,25 @@ class FileManager extends Plugin {
return await this._setFileInternal(path, content) return await this._setFileInternal(path, content)
} }
async setMultipleFileContent(path, content, folderPath, alert) {
if (this.currentRequest) {
const canCall = await this.askUserPermission(`writeFile`, `modifying ${folderPath} ...`)
const required = this.appManager.isRequired(this.currentRequest.from)
if (canCall && !required && alert) {
// inform the user about modification after permission is granted and even if permission was saved before
this.call('notification', 'toast', fileChangedToastMsg(this.currentRequest.from, folderPath))
}
}
return await this._setFileInternal(path, content)
}
_setFileInternal(path, content) { _setFileInternal(path, content) {
const provider = this.fileProviderOf(path) const provider = this.fileProviderOf(path)
if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` }) if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` })
// TODO : Add permission // TODO : Add permission
// TODO : Change Provider to Promise // TODO : Change Provider to Promise
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
provider.set(path, content, (error) => { provider.set(path, content, async (error) => {
if (error) reject(error) if (error) reject(error)
this.syncEditor(path) this.syncEditor(path)
this.emit('fileSaved', path) this.emit('fileSaved', path)

@ -6,7 +6,7 @@ import { QueryParams } from '@remix-project/remix-lib'
const profile: Profile = { const profile: Profile = {
name: 'layout', name: 'layout',
description: 'layout', description: 'layout',
methods: ['minimize', 'maximiseSidePanel', 'resetSidePanel'] methods: ['minimize', 'maximiseSidePanel', 'resetSidePanel', 'maximizeTerminal']
} }
interface panelState { interface panelState {
@ -109,6 +109,12 @@ export class Layout extends Plugin {
this.maximised[current] = true this.maximised[current] = true
} }
async maximizeTerminal() {
this.panels.terminal.minimized = false
this.event.emit('change', this.panels)
this.emit('change', this.panels)
}
async resetSidePanel () { async resetSidePanel () {
this.event.emit('resetsidepanel') this.event.emit('resetsidepanel')
const current = await this.call('sidePanel', 'currentFocus') const current = await this.call('sidePanel', 'currentFocus')

@ -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<CreateChatCompletionResponse> {
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
}
}

@ -477,40 +477,68 @@ export class CodeParser extends Plugin {
*/ */
async definitionAtPosition(position: number) { async definitionAtPosition(position: number) {
const nodes = await this.nodesAtPosition(position) const nodes = await this.nodesAtPosition(position)
let nodeDefinition: any const nodeDefinition = {
'ast': null,
'parser': null
}
let node: genericASTNode let node: genericASTNode
if (nodes && nodes.length && !this.errorState) { if (nodes && nodes.length) {
node = nodes[nodes.length - 1] node = nodes[nodes.length - 1]
nodeDefinition = node let astNodeDefinition = node
if (!isNodeDefinition(node)) { if (!isNodeDefinition(node)) {
nodeDefinition = (await this.declarationOf(node)) || node astNodeDefinition = (await this.declarationOf(node)) || node
} }
if (node.nodeType === 'ImportDirective') { if (node.nodeType === 'ImportDirective') {
for (const key in this.nodeIndex.flatReferences) { for (const key in this.nodeIndex.flatReferences) {
if (this.nodeIndex.flatReferences[key].id === node.sourceUnit) { if (this.nodeIndex.flatReferences[key].id === node.sourceUnit) {
nodeDefinition = this.nodeIndex.flatReferences[key] astNodeDefinition = this.nodeIndex.flatReferences[key]
} }
} }
} }
return nodeDefinition
} else { nodeDefinition.ast = astNodeDefinition
}
const astNodes = await this.antlrService.listAstNodes() const astNodes = await this.antlrService.listAstNodes()
let parserNodeDefinition = null
if (astNodes && astNodes.length) { if (astNodes && astNodes.length) {
for (const node of astNodes) { for (const node of astNodes) {
if (node.range[0] <= position && node.range[1] >= position) { if (node.range[0] <= position && node.range[1] >= position) {
if (nodeDefinition && nodeDefinition.range[0] < node.range[0]) { if (parserNodeDefinition && parserNodeDefinition.range[0] < node.range[0]) {
nodeDefinition = node parserNodeDefinition = node
}
if (!parserNodeDefinition) parserNodeDefinition = node
}
}
if (parserNodeDefinition && parserNodeDefinition.type && parserNodeDefinition.type === 'Identifier') {
const nodeForIdentifier = await this.findIdentifier(parserNodeDefinition)
if (nodeForIdentifier) parserNodeDefinition = nodeForIdentifier
} }
if (!nodeDefinition) nodeDefinition = node nodeDefinition.parser = parserNodeDefinition
} }
/* 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
*/
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
} }
if (nodeDefinition && nodeDefinition.type && nodeDefinition.type === 'Identifier') {
const nodeForIdentifier = await this.findIdentifier(nodeDefinition)
if (nodeForIdentifier) nodeDefinition = nodeForIdentifier
} }
return nodeDefinition
} }
if (nodeDefinition.ast && !nodeDefinition.parser) {
return nodeDefinition.ast
} }
return nodeDefinition.parser
} }
async getContractNodes(contractName: string) { async getContractNodes(contractName: string) {

@ -99,11 +99,11 @@ export default class CodeParserCompiler {
await this.clearDecorators(result.getSourceCode().sources) await this.clearDecorators(result.getSourceCode().sources)
} }
if (!data.sources) return if (!data.sources) return
if (data.sources && Object.keys(data.sources).length === 0) return if (data.sources && Object.keys(data.sources).length === 0) return
this.plugin.compilerAbstract = new CompilerAbstract('soljson', data, source, input) this.plugin.compilerAbstract = new CompilerAbstract('soljson', data, source, input)
this.errorState = false this.errorState = false
this.plugin.nodeIndex = { this.plugin.nodeIndex = {
declarations: {}, declarations: {},
flatReferences: {}, flatReferences: {},
@ -113,7 +113,10 @@ export default class CodeParserCompiler {
this.plugin._buildIndex(data, source) 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 // 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) 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() await this.plugin.gasService.showGasEstimates()
this.plugin.emit('astFinished') this.plugin.emit('astFinished')
} }

@ -42,7 +42,10 @@ export default class CodeParserGasService {
} }
this.plugin.currentFile = await this.plugin.call('fileManager', 'file') 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 // 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 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 gasEstimates = await this.getGasEstimates(this.plugin.currentFile)

@ -1,5 +1,5 @@
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import {InjectedL2Provider} from './injected-L2-provider' import {InjectedCustomProvider} from './injected-custom-provider'
const profile = { const profile = {
name: 'injected-arbitrum-one-provider', name: 'injected-arbitrum-one-provider',
@ -10,7 +10,7 @@ const profile = {
version: packageJson.version version: packageJson.version
} }
export class InjectedArbitrumOneProvider extends InjectedL2Provider { export class InjectedArbitrumOneProvider extends InjectedCustomProvider {
constructor() { constructor() {
super(profile, 'Arbitrum One', '0xa4b1', ['https://arb1.arbitrum.io/rpc']) super(profile, 'Arbitrum One', '0xa4b1', ['https://arb1.arbitrum.io/rpc'])
} }

@ -1,26 +1,30 @@
import {InjectedProviderDefaultBase} from './injected-provider-default' import {InjectedProviderDefaultBase} from './injected-provider-default'
export class InjectedL2Provider extends InjectedProviderDefaultBase { export class InjectedCustomProvider extends InjectedProviderDefaultBase {
chainName: string chainName: string
chainId: string chainId: string
rpcUrls: Array<string> rpcUrls: Array<string>
nativeCurrency: Record<string, any>
blockExplorerUrls: Array<string>
constructor(profile: any, chainName: string, chainId: string, rpcUrls: Array<string>) { constructor(profile: any, chainName: string, chainId: string, rpcUrls: Array<string>, nativeCurrency?: Record<string, any>, blockExplorerUrls?: Array<string>) {
super(profile) super(profile)
this.chainName = chainName this.chainName = chainName
this.chainId = chainId this.chainId = chainId
this.rpcUrls = rpcUrls this.rpcUrls = rpcUrls
this.nativeCurrency = nativeCurrency
this.blockExplorerUrls = blockExplorerUrls
} }
async init() { async init() {
await super.init() await super.init()
if (this.chainName && this.rpcUrls && this.rpcUrls.length > 0) await addL2Network(this.chainName, this.chainId, this.rpcUrls) 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 L2 network to main injected provider') else throw new Error('Cannot add the custom network to main injected provider')
return {} return {}
} }
} }
export const addL2Network = async (chainName: string, chainId: string, rpcUrls: Array<string>) => { export const addCustomNetwork = async (chainName: string, chainId: string, rpcUrls: Array<string>, nativeCurrency?: Record<string, any>, blockExplorerUrls?: Array<string>) => {
try { try {
await (window as any).ethereum.request({ await (window as any).ethereum.request({
method: 'wallet_switchEthereumChain', method: 'wallet_switchEthereumChain',
@ -30,15 +34,16 @@ export const addL2Network = async (chainName: string, chainId: string, rpcUrls:
// This error code indicates that the chain has not been added to MetaMask. // This error code indicates that the chain has not been added to MetaMask.
if (switchError.code === 4902) { if (switchError.code === 4902) {
try { try {
await (window as any).ethereum.request({ const paramsObj: Record<string, any> = {
method: 'wallet_addEthereumChain',
params: [
{
chainId: chainId, chainId: chainId,
chainName: chainName, chainName: chainName,
rpcUrls: rpcUrls 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({ await (window as any).ethereum.request({

@ -0,0 +1,30 @@
import * as packageJson from '../../../../../package.json'
import {InjectedCustomProvider} from './injected-custom-provider'
const profile = {
name: 'injected-ephemery-testnet-provider',
displayName: 'Injected Ephemery Testnet Provider',
kind: 'provider',
description: 'Injected Ephemery Testnet Provider',
methods: ['sendAsync', 'init'],
version: packageJson.version
}
export class InjectedEphemeryTestnetProvider extends InjectedCustomProvider {
constructor() {
super(profile,
'Ephemery Testnet',
'',
['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/'
]
)
}
}

@ -1,5 +1,5 @@
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import {InjectedL2Provider} from './injected-L2-provider' import {InjectedCustomProvider} from './injected-custom-provider'
const profile = { const profile = {
name: 'injected-optimism-provider', name: 'injected-optimism-provider',
@ -10,7 +10,7 @@ const profile = {
version: packageJson.version version: packageJson.version
} }
export class Injected0ptimismProvider extends InjectedL2Provider { export class Injected0ptimismProvider extends InjectedCustomProvider {
constructor() { constructor() {
super(profile, 'Optimism', '0xa', ['https://mainnet.optimism.io']) super(profile, 'Optimism', '0xa', ['https://mainnet.optimism.io'])
} }

@ -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
}
)
}
}

@ -6,7 +6,7 @@ import * as packageJson from '../../../../../package.json'
const EventManager = require('../../lib/events') const EventManager = require('../../lib/events')
const Recorder = require('../tabs/runTab/model/recorder.js') const Recorder = require('../tabs/runTab/model/recorder.js')
const _paq = window._paq = window._paq || [] const _paq = (window._paq = window._paq || [])
const profile = { const profile = {
name: 'udapp', name: 'udapp',
@ -20,7 +20,17 @@ const profile = {
maintainedBy: 'Remix', maintainedBy: 'Remix',
permission: true, permission: true,
events: ['newTransaction'], 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 { export class RunTab extends ViewPlugin {
@ -91,7 +101,11 @@ export class RunTab extends ViewPlugin {
} }
render() { render() {
return <div><RunTabUI plugin={this} /></div> return (
<div>
<RunTabUI plugin={this} />
</div>
)
} }
onReady(api) { onReady(api) {
@ -119,6 +133,7 @@ export class RunTab extends ViewPlugin {
} }
}, },
provider: { provider: {
async sendAsync (payload) { async sendAsync (payload) {
return udapp.call(name, 'sendAsync', payload) return udapp.call(name, 'sendAsync', payload)
} }
@ -129,10 +144,17 @@ export class RunTab extends ViewPlugin {
// basic injected // basic injected
// if it's the trust wallet provider, we have a specific provider for that, see below // 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)) { if (window && window.ethereum && !(window.ethereum.isTrustWallet || window.ethereum.selectedProvider?.isTrustWallet)) {
const displayNameInjected = `Injected Provider${(window && window.ethereum && !(window.ethereum.providers && !window.ethereum.selectedProvider)) ? const displayNameInjected = `Injected Provider${
window.ethereum.isCoinbaseWallet || window.ethereum.selectedProvider?.isCoinbaseWallet ? ' - Coinbase' : window && window.ethereum && !(window.ethereum.providers && !window.ethereum.selectedProvider)
window.ethereum.isBraveWallet || window.ethereum.selectedProvider?.isBraveWallet ? ' - Brave' : ? window.ethereum.isCoinbaseWallet || window.ethereum.selectedProvider?.isCoinbaseWallet
window.ethereum.isMetaMask || window.ethereum.selectedProvider?.isMetaMask ? ' - MetaMask' : '' : ''}` ? ' - Coinbase'
: window.ethereum.isBraveWallet || window.ethereum.selectedProvider?.isBraveWallet
? ' - Brave'
: window.ethereum.isMetaMask || window.ethereum.selectedProvider?.isMetaMask
? ' - MetaMask'
: ''
: ''
}`
await addProvider('injected', displayNameInjected, true, false) await addProvider('injected', displayNameInjected, true, false)
} else if (window && !window.ethereum) { } else if (window && !window.ethereum) {
// we still add "injected" if there's no provider (just so it's visible to the user). // we still add "injected" if there's no provider (just so it's visible to the user).
@ -158,6 +180,10 @@ export class RunTab extends ViewPlugin {
// wallet connect // wallet connect
await addProvider('walletconnect', 'WalletConnect', false, false) 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 // external provider
await addProvider('basic-http-provider', 'Custom - External Http Provider', false, false) await addProvider('basic-http-provider', 'Custom - External Http Provider', false, false)
await addProvider('hardhat-provider', 'Dev - Hardhat Provider', false, false) await addProvider('hardhat-provider', 'Dev - Hardhat Provider', false, false)

@ -2,34 +2,117 @@ import { PluginManager } from '@remixproject/engine'
import {EventEmitter} from 'events' import {EventEmitter} from 'events'
import {QueryParams} from '@remix-project/remix-lib' import {QueryParams} from '@remix-project/remix-lib'
import {IframePlugin} from '@remixproject/engine-web' import {IframePlugin} from '@remixproject/engine-web'
const _paq = window._paq = window._paq || [] const _paq = (window._paq = window._paq || [])
// requiredModule removes the plugin from the plugin manager list on UI // requiredModule removes the plugin from the plugin manager list on UI
const requiredModules = [ // services + layout views + system views const requiredModules = [
'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'locale', // services + layout views + system views
'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'manager',
'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout', 'config',
'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy', 'compilerArtefacts',
'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', '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', 'vm-shanghai',
'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser', 'codeFormatter', 'solidityumlgen', 'contractflattener', 'solidity-script'] 'compileAndRun',
'search',
'recorder',
'fileDecorator',
'codeParser',
'codeFormatter',
'solidityumlgen',
'contractflattener',
'solidity-script'
]
// dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd)
const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither'] 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 = { const sensitiveCalls = {
'fileManager': ['writeFile', 'copyFile', 'rename', 'copyDir'], fileManager: ['writeFile', 'copyFile', 'rename', 'copyDir'],
'contentImport': ['resolveAndSave'], contentImport: ['resolveAndSave'],
'web3Provider': ['sendAsync'], web3Provider: ['sendAsync']
} }
export function isNative(name) { export function isNative(name) {
// nativePlugin allows to bypass the permission request // nativePlugin allows to bypass the permission request
const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'solidity-logic', 'solidityStaticAnalysis', 'solidityUnitTesting', const nativePlugins = [
'layout', 'notification', 'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected-optimism-provider', 'vyper',
'tabs', 'injected-arbitrum-one-provider', 'injected', 'doc-gen', 'doc-viewer'] '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) return nativePlugins.includes(name) || requiredModules.includes(name)
} }
@ -44,9 +127,7 @@ export function isNative(name) {
* @returns {boolean} * @returns {boolean}
*/ */
export function canActivate(from, to) { export function canActivate(from, to) {
return ['ethdoc'].includes(from.name) || return ['ethdoc'].includes(from.name) || isNative(from.name) || (to && from && from.canActivate && from.canActivate.includes(to.name))
isNative(from.name) ||
(to && from && from.canActivate && from.canActivate.includes(to.name))
} }
export class RemixAppManager extends PluginManager { export class RemixAppManager extends PluginManager {
@ -72,10 +153,7 @@ export class RemixAppManager extends PluginManager {
async deactivatePlugin(name) { async deactivatePlugin(name) {
const profile = await this.getProfile(name) const profile = await this.getProfile(name)
const [to, from] = [ const [to, from] = [profile, await this.getProfile(this.requestFrom)]
profile,
await this.getProfile(this.requestFrom)
]
if (this.canDeactivatePlugin(from, to)) { if (this.canDeactivatePlugin(from, to)) {
if (profile.methods.includes('deactivate')) { if (profile.methods.includes('deactivate')) {
try { try {
@ -104,7 +182,10 @@ export class RemixAppManager extends PluginManager {
} }
onPluginActivated(plugin) { 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.event.emit('activate', plugin)
this.emit('activate', plugin) this.emit('activate', plugin)
if (!requiredModules.includes(plugin.name)) _paq.push(['trackEvent', 'pluginManager', 'activate', plugin.name]) if (!requiredModules.includes(plugin.name)) _paq.push(['trackEvent', 'pluginManager', 'activate', plugin.name])
@ -121,7 +202,10 @@ export class RemixAppManager extends PluginManager {
} }
onPluginDeactivated(plugin) { 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) this.event.emit('deactivate', plugin)
_paq.push(['trackEvent', 'pluginManager', 'deactivate', plugin.name]) _paq.push(['trackEvent', 'pluginManager', 'deactivate', plugin.name])
} }
@ -142,7 +226,7 @@ export class RemixAppManager extends PluginManager {
plugins = await res.json() plugins = await res.json()
plugins = plugins.filter((plugin) => { plugins = plugins.filter((plugin) => {
if (plugin.targets && Array.isArray(plugin.targets) && plugin.targets.length > 0) { if (plugin.targets && Array.isArray(plugin.targets) && plugin.targets.length > 0) {
return (plugin.targets.includes('remix')) return plugin.targets.includes('remix')
} }
return true return true
}) })
@ -177,7 +261,7 @@ export class RemixAppManager extends PluginManager {
} }
} }
return plugins.map(plugin => { return plugins.map((plugin) => {
if (plugin.name === testPluginName) plugin.url = testPluginUrl if (plugin.name === testPluginName) plugin.url = testPluginUrl
return new IframePlugin(plugin) return new IframePlugin(plugin)
}) })
@ -249,11 +333,15 @@ class PluginLoader {
const saved = actives.filter((name) => !this.donotAutoReload.includes(name)) const saved = actives.filter((name) => !this.donotAutoReload.includes(name))
localStorage.setItem('workspace', JSON.stringify(saved)) localStorage.setItem('workspace', JSON.stringify(saved))
}, },
get: () => { return JSON.parse(localStorage.getItem('workspace')) } get: () => {
return JSON.parse(localStorage.getItem('workspace'))
}
} }
this.loaders.queryParams = { this.loaders.queryParams = {
set: () => { /* Do nothing. */ }, set: () => {
/* Do nothing. */
},
get: () => { get: () => {
const {activate} = queryParams.get() const {activate} = queryParams.get()
if (!activate) return [] if (!activate) return []

@ -20,6 +20,7 @@ export class RemixEngine extends Engine {
if (name === 'fetchAndCompile') return { queueTimeout: 60000 * 4 } if (name === 'fetchAndCompile') return { queueTimeout: 60000 * 4 }
if (name === 'walletconnect') return { queueTimeout: 60000 * 4 } if (name === 'walletconnect') return { queueTimeout: 60000 * 4 }
if (name === 'udapp') return { queueTimeout: 60000 * 4 } if (name === 'udapp') return { queueTimeout: 60000 * 4 }
if (name === 'circuit-compiler') return { queueTimeout: 60000 * 4 }
return { queueTimeout: 10000 } return { queueTimeout: 10000 }
} }

@ -1,11 +1,11 @@
# Team best practices # 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-ide https://github.com/ethereum/remix-project
- remix-plugin https://github.com/ethereum/remix-plugin - 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). This document link to other specialised best practices (like coding best practices).
Related links: Related links:
@ -32,22 +32,22 @@ Related links:
- Daily standup (1pm CET - 11am GMT) for taking care of the current issues. - 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 every contributor on what others are doing.
- Update the prioritised issues / PRs list. - Update the prioritised issues / PRs list.
- Address little issues (possibly related to the current ongoing milestone). - Address little issues (possibly related to the current ongoing milestone).
- High level demo, explanation about specific points of the codebase or Ethereum related things. - 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: ### 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 story fits into the Ethereum tech.
- How the backend (if any) works / will work (could be a smart contract). - How the backend (if any) works / will work (could be a smart contract).
- How the frontend works / will work. - 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. - 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) - 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). - 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. - 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. - 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: ### 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 - 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 - 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 - 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: ### maintenance:
- Setting up a "bug" time where we each take a bug for which: - 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 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: ### documentation:
- We set up a special day where we address all the necessary documentation work in a team effort. - We set up a special day where we address all the necessary documentation work in a team effort.
- Change to markdown or gitbook - Change to markdown or gitbook
### support: ### 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. - 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 - People should be pointed to the appropriate `best practice.md` files by team members
### code best practices: ### code best practices:

@ -2,9 +2,20 @@ import { PluginClient } from '@remixproject/plugin'
import {createClient} from '@remixproject/plugin-webview' import {createClient} from '@remixproject/plugin-webview'
import {w3mConnectors, w3mProvider} from '@web3modal/ethereum' import {w3mConnectors, w3mProvider} from '@web3modal/ethereum'
import {createConfig, configureChains} from 'wagmi' import {createConfig, configureChains} from 'wagmi'
import { arbitrum, arbitrumGoerli, mainnet, polygon, polygonMumbai, optimism, optimismGoerli, Chain, goerli, sepolia } from 'viem/chains' import {
arbitrum,
arbitrumGoerli,
mainnet,
polygon,
polygonMumbai,
optimism,
optimismGoerli,
Chain,
goerli,
sepolia
} from 'viem/chains'
import {EthereumClient} from '@web3modal/ethereum' import {EthereumClient} from '@web3modal/ethereum'
import EventManager from "events" import EventManager from 'events'
import {PROJECT_ID} from './constant' import {PROJECT_ID} from './constant'
export class WalletConnectRemixClient extends PluginClient { export class WalletConnectRemixClient extends PluginClient {
@ -18,7 +29,7 @@ export class WalletConnectRemixClient extends PluginClient {
super() super()
createClient(this) createClient(this)
this.internalEvents = new EventManager() this.internalEvents = new EventManager()
this.methods = ["sendAsync", "init", "deactivate"] this.methods = ['sendAsync', 'init', 'deactivate']
this.onload() this.onload()
} }
@ -35,8 +46,20 @@ export class WalletConnectRemixClient extends PluginClient {
async initClient() { async initClient() {
try { try {
this.chains = [arbitrum, arbitrumGoerli, mainnet, polygon, polygonMumbai, optimism, optimismGoerli, goerli, sepolia] this.chains = [
const { publicClient } = configureChains(this.chains, [w3mProvider({ projectId: PROJECT_ID })]) mainnet,
arbitrum,
arbitrumGoerli,
polygon,
polygonMumbai,
optimism,
optimismGoerli,
goerli,
sepolia
]
const {publicClient} = configureChains(this.chains, [
w3mProvider({projectId: PROJECT_ID})
])
this.wagmiConfig = createConfig({ this.wagmiConfig = createConfig({
autoConnect: false, autoConnect: false,
@ -45,7 +68,7 @@ export class WalletConnectRemixClient extends PluginClient {
}) })
this.ethereumClient = new EthereumClient(this.wagmiConfig, this.chains) this.ethereumClient = new EthereumClient(this.wagmiConfig, this.chains)
} catch (e) { } catch (e) {
return console.error("Could not get a wallet connection", e) return console.error('Could not get a wallet connection', e)
} }
} }
@ -68,19 +91,41 @@ export class WalletConnectRemixClient extends PluginClient {
}) })
} }
sendAsync (data: { method: string, params: string, id: string }) { async sendAsync(data: {method: string; params: string; id: string}) {
return new Promise((resolve, reject) => { if (this.wagmiConfig.status === 'connected') {
if (this.wagmiConfig) { if (data.method === 'eth_accounts') {
this.wagmiConfig.publicClient.request(data).then((message) => { return {
resolve({"jsonrpc": "2.0", "result": message, "id": data.id}) jsonrpc: '2.0',
}).catch((error) => { result: [this.wagmiConfig.data.account],
reject(error) id: data.id
}) }
} else { } else {
console.error(`Cannot make ${data.method} request. Remix client is not connect to walletconnect client`) const provider = await this.wagmiConfig.connector.getProvider({
resolve({"jsonrpc": "2.0", "result": [], "id": data.id}) 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() { async deactivate() {

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/ghaction-helper", "name": "@remix-project/ghaction-helper",
"version": "0.1.11", "version": "0.1.12",
"description": "Solidity Tests GitHub Action Helper", "description": "Solidity Tests GitHub Action Helper",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
@ -19,17 +19,18 @@
}, },
"homepage": "https://github.com/ethereum/remix-project#readme", "homepage": "https://github.com/ethereum/remix-project#readme",
"devDependencies": { "devDependencies": {
"@remix-project/remix-solidity": "^0.5.17", "@remix-project/remix-solidity": "^0.5.18",
"@types/chai": "^4.3.4", "@types/chai": "^4.3.4",
"typescript": "^4.9.3" "typescript": "^4.9.3"
}, },
"dependencies": { "dependencies": {
"@ethereum-waffle/chai": "^3.4.4", "@ethereum-waffle/chai": "^3.4.4",
"@remix-project/remix-simulator": "^0.2.31", "@remix-project/remix-simulator": "^0.2.32",
"chai": "^4.3.7", "chai": "^4.3.7",
"ethers": "^5.7.2", "ethers": "^5.7.2",
"web3": "^4.1.1" "web3": "^4.1.1"
}, },
"types": "./src/index.d.ts", "types": "./src/index.d.ts",
"gitHead": "b11b11623729f741a5ccd387bc60dc5db41f28ab"
"gitHead": "335beb044cbd9d58c255bd8441a310757c99bf40"
} }

@ -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. 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 ### License
MIT © 2018-21 Remix Team MIT © 2018-21 Remix Team

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-analyzer", "name": "@remix-project/remix-analyzer",
"version": "0.5.40", "version": "0.5.41",
"description": "Tool to perform static analysis on Solidity smart contracts", "description": "Tool to perform static analysis on Solidity smart contracts",
"scripts": { "scripts": {
"test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts" "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/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5", "@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1", "@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-astwalker": "^0.0.61", "@remix-project/remix-astwalker": "^0.0.62",
"@remix-project/remix-lib": "^0.5.38", "@remix-project/remix-lib": "^0.5.39",
"async": "^2.6.2", "async": "^2.6.2",
"ethers": "^5.4.2", "ethers": "^5.4.2",
"ethjs-util": "^0.1.6", "ethjs-util": "^0.1.6",
@ -50,6 +50,6 @@
"typescript": "^3.7.5" "typescript": "^3.7.5"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "b11b11623729f741a5ccd387bc60dc5db41f28ab", "gitHead": "335beb044cbd9d58c255bd8441a310757c99bf40",
"main": "./src/index.js" "main": "./src/index.js"
} }

@ -35,7 +35,7 @@ astWalker.on("node", node => {
Please feel free to open an issue or a pull request. 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 ### License
MIT © 2018-21 Remix Team MIT © 2018-21 Remix Team

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-astwalker", "name": "@remix-project/remix-astwalker",
"version": "0.0.61", "version": "0.0.62",
"description": "Tool to walk through Solidity AST", "description": "Tool to walk through Solidity AST",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
@ -37,7 +37,7 @@
"@ethereumjs/tx": "^4.1.1", "@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5", "@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1", "@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-lib": "^0.5.38", "@remix-project/remix-lib": "^0.5.39",
"@types/tape": "^4.2.33", "@types/tape": "^4.2.33",
"async": "^2.6.2", "async": "^2.6.2",
"ethers": "^5.4.2", "ethers": "^5.4.2",
@ -53,6 +53,6 @@
"tap-spec": "^5.0.0" "tap-spec": "^5.0.0"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "b11b11623729f741a5ccd387bc60dc5db41f28ab", "gitHead": "335beb044cbd9d58c255bd8441a310757c99bf40",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -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) [![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) [![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 ### Installation
`@remix-project/remix-debug` is an NPM package and can be installed using NPM as: `@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. 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 ### License
MIT © 2018-21 Remix Team MIT © 2018-21 Remix Team

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-debug", "name": "@remix-project/remix-debug",
"version": "0.5.31", "version": "0.5.32",
"description": "Tool to debug Ethereum transactions", "description": "Tool to debug Ethereum transactions",
"contributors": [ "contributors": [
{ {
@ -26,10 +26,10 @@
"@ethereumjs/tx": "^4.1.1", "@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5", "@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1", "@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-astwalker": "^0.0.61", "@remix-project/remix-astwalker": "^0.0.62",
"@remix-project/remix-lib": "^0.5.38", "@remix-project/remix-lib": "^0.5.39",
"@remix-project/remix-simulator": "^0.2.31", "@remix-project/remix-simulator": "^0.2.32",
"@remix-project/remix-solidity": "^0.5.17", "@remix-project/remix-solidity": "^0.5.18",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^2.6.2", "async": "^2.6.2",
"color-support": "^1.1.3", "color-support": "^1.1.3",
@ -69,6 +69,6 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "b11b11623729f741a5ccd387bc60dc5db41f28ab", "gitHead": "335beb044cbd9d58c255bd8441a310757c99bf40",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -19,7 +19,7 @@ export function setProvider (web3, url) {
export function web3DebugNode (network) { export function web3DebugNode (network) {
const web3DebugNodes = { 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', Rinkeby: 'https://remix-rinkeby.ethdevops.io',
Ropsten: 'https://remix-ropsten.ethdevops.io', Ropsten: 'https://remix-ropsten.ethdevops.io',
Goerli: 'https://remix-goerli.ethdevops.io', Goerli: 'https://remix-goerli.ethdevops.io',

@ -43,7 +43,7 @@
Please feel free to open an issue or a pull request. 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 ### License
MIT © 2018-21 Remix Team MIT © 2018-21 Remix Team

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-lib", "name": "@remix-project/remix-lib",
"version": "0.5.38", "version": "0.5.39",
"description": "Library to various Remix tools", "description": "Library to various Remix tools",
"contributors": [ "contributors": [
{ {
@ -53,6 +53,6 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "b11b11623729f741a5ccd387bc60dc5db41f28ab", "gitHead": "335beb044cbd9d58c255bd8441a310757c99bf40",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -86,7 +86,7 @@
Please feel free to open an issue or a pull request. 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 ### License
MIT © 2018-21 Remix Team MIT © 2018-21 Remix Team

@ -26,14 +26,19 @@ program
.option('-c, --coinbase [coinbase]', 'specify coinbase', '0x0000000000000000000000000000000000000000') .option('-c, --coinbase [coinbase]', 'specify coinbase', '0x0000000000000000000000000000000000000000')
.option('--rpc', 'run rpc server only', true) .option('--rpc', 'run rpc server only', true)
.option('--details', 'display payloads for every requests and their responses', false) .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 = require('../src/server')
const server = new Server({ const server = new Server({
coinbase: program.coinbase, coinbase: option.coinbase,
rpc: program.rpc, rpc: option.rpc,
logDetails: program.details logDetails: option.details
}) })
server.start(program.host, program.port) server.start(option.ip, option.port)
}) })
program.parse(process.argv) program.parse(process.argv)

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-simulator", "name": "@remix-project/remix-simulator",
"version": "0.2.31", "version": "0.2.32",
"description": "Ethereum IDE and tools for the web", "description": "Ethereum IDE and tools for the web",
"contributors": [ "contributors": [
{ {
@ -22,7 +22,7 @@
"@ethereumjs/tx": "^4.1.1", "@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5", "@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1", "@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-lib": "^0.5.38", "@remix-project/remix-lib": "^0.5.39",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^3.1.0", "async": "^3.1.0",
"body-parser": "^1.18.2", "body-parser": "^1.18.2",
@ -68,6 +68,6 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "b11b11623729f741a5ccd387bc60dc5db41f28ab", "gitHead": "335beb044cbd9d58c255bd8441a310757c99bf40",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-solidity", "name": "@remix-project/remix-solidity",
"version": "0.5.17", "version": "0.5.18",
"description": "Tool to load and run Solidity compiler", "description": "Tool to load and run Solidity compiler",
"main": "src/index.js", "main": "src/index.js",
"types": "src/index.d.ts", "types": "src/index.d.ts",
@ -19,7 +19,7 @@
"@ethereumjs/tx": "^4.1.1", "@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5", "@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1", "@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-lib": "^0.5.38", "@remix-project/remix-lib": "^0.5.39",
"async": "^2.6.2", "async": "^2.6.2",
"eslint-scope": "^5.0.0", "eslint-scope": "^5.0.0",
"ethers": "^5.4.2", "ethers": "^5.4.2",
@ -57,5 +57,5 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "b11b11623729f741a5ccd387bc60dc5db41f28ab" "gitHead": "335beb044cbd9d58c255bd8441a310757c99bf40"
} }

@ -81,12 +81,15 @@ export class Compiler {
* @param missingInputs missing import file path list * @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) => { this.gatherImports(files, missingInputs, (error, input) => {
if (error) { if (error) {
this.state.lastCompilationResult = null this.state.lastCompilationResult = null
this.event.trigger('compilationFinished', [false, { error: { formattedMessage: error, severity: 'error' } }, files, input, this.state.currentVersion]) 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.target = target
this.state.compilationStartTime = new Date().getTime() this.state.compilationStartTime = new Date().getTime()
this.event.trigger('compilationStarted', []) this.event.trigger('compilationStarted', [])
this.internalCompile(files) this.internalCompile(files, null, this.state.compilationStartTime)
} }
/** /**
@ -157,7 +160,7 @@ export class Compiler {
* @param source Source * @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 let noFatalErrors = true // ie warnings are ok
const checkIfFatalError = (error: CompilationError) => { const checkIfFatalError = (error: CompilationError) => {
@ -173,7 +176,7 @@ export class Compiler {
this.event.trigger('compilationFinished', [false, data, source, input, version]) this.event.trigger('compilationFinished', [false, data, source, input, version])
} else if (missingInputs !== undefined && missingInputs.length > 0 && source && source.sources) { } else if (missingInputs !== undefined && missingInputs.length > 0 && source && source.sources) {
// try compiling again with the new set of inputs // try compiling again with the new set of inputs
this.internalCompile(source.sources, missingInputs) this.internalCompile(source.sources, missingInputs, timeStamp)
} else { } else {
data = this.updateInterface(data) data = this.updateInterface(data)
if (source) { if (source) {
@ -292,6 +295,7 @@ export class Compiler {
this.state.worker.addEventListener('message', (msg: Record<'data', MessageFromWorker>) => { this.state.worker.addEventListener('message', (msg: Record<'data', MessageFromWorker>) => {
const data: MessageFromWorker = msg.data const data: MessageFromWorker = msg.data
if (this.state.compilerRetriggerMode == CompilerRetriggerMode.retrigger && data.timestamp !== this.state.compilationStartTime) { if (this.state.compilerRetriggerMode == CompilerRetriggerMode.retrigger && data.timestamp !== this.state.compilationStartTime) {
// drop message from previous compilation
return return
} }
switch (data.cmd) { switch (data.cmd) {
@ -312,7 +316,7 @@ export class Compiler {
sources = jobs[data.job].sources sources = jobs[data.job].sources
delete jobs[data.job] delete jobs[data.job]
} }
this.onCompilationFinished(result, data.missingInputs, sources, data.input, this.state.currentVersion) this.onCompilationFinished(result, data.missingInputs, sources, data.input, this.state.currentVersion, data.timestamp)
} }
break break
} }
@ -325,7 +329,7 @@ export class Compiler {
this.onCompilationFinished({ error: { formattedMessage } }) this.onCompilationFinished({ error: { formattedMessage } })
}) })
this.state.compileJSON = (source: SourceWithTarget) => { this.state.compileJSON = (source: SourceWithTarget, timeStamp: number) => {
if (source && source.sources) { if (source && source.sources) {
const { optimize, runs, evmVersion, language, useFileConfiguration, configFileContent } = this.state const { optimize, runs, evmVersion, language, useFileConfiguration, configFileContent } = this.state
jobs.push({ sources: source }) jobs.push({ sources: source })
@ -342,12 +346,11 @@ export class Compiler {
return return
} }
this.state.worker.postMessage({ this.state.worker.postMessage({
cmd: 'compile', cmd: 'compile',
job: jobs.length - 1, job: jobs.length - 1,
input: input, input: input,
timestamp: this.state.compilationStartTime timestamp: timeStamp
}) })
} }
} }

@ -160,7 +160,7 @@ export enum CompilerRetriggerMode {
} }
export interface CompilerState { export interface CompilerState {
compileJSON: ((input: SourceWithTarget) => void) | null, compileJSON: ((input: SourceWithTarget, timeStamp?: number) => void) | null,
worker: any, worker: any,
currentVersion: string| null| undefined, currentVersion: string| null| undefined,
compilerLicense: string| null compilerLicense: string| null

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-tests", "name": "@remix-project/remix-tests",
"version": "0.2.31", "version": "0.2.32",
"description": "Tool to test Solidity smart contracts", "description": "Tool to test Solidity smart contracts",
"main": "src/index.js", "main": "src/index.js",
"types": "./src/index.d.ts", "types": "./src/index.d.ts",
@ -41,9 +41,9 @@
"@ethereumjs/tx": "^4.1.1", "@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5", "@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1", "@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-lib": "^0.5.38", "@remix-project/remix-lib": "^0.5.39",
"@remix-project/remix-simulator": "^0.2.31", "@remix-project/remix-simulator": "^0.2.32",
"@remix-project/remix-solidity": "^0.5.17", "@remix-project/remix-solidity": "^0.5.18",
"@remix-project/remix-url-resolver": "^0.0.42", "@remix-project/remix-url-resolver": "^0.0.42",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^2.6.0", "async": "^2.6.0",
@ -78,5 +78,5 @@
"typescript": "^3.3.1" "typescript": "^3.3.1"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "b11b11623729f741a5ccd387bc60dc5db41f28ab" "gitHead": "335beb044cbd9d58c255bd8441a310757c99bf40"
} }

@ -1,7 +1,7 @@
import { Monaco } from "@monaco-editor/react" import {Monaco} from '@monaco-editor/react'
import monaco from "../../types/monaco" import monaco from '../../types/monaco'
import { EditorUIProps } from "../remix-ui-editor" import {EditorUIProps} from '../remix-ui-editor'
import { default as fixesList } from "./quickfixes" import {default as fixesList} from './quickfixes'
export class RemixCodeActionProvider implements monaco.languages.CodeActionProvider { export class RemixCodeActionProvider implements monaco.languages.CodeActionProvider {
props: EditorUIProps props: EditorUIProps
@ -22,27 +22,80 @@ export class RemixCodeActionProvider implements monaco.languages.CodeActionProvi
let fixes: Record<string, any>[], msg: string let fixes: Record<string, any>[], msg: string
let isOldAST: boolean = false let isOldAST: boolean = false
const errStrings: string[] = Object.keys(fixesList) const errStrings: string[] = Object.keys(fixesList)
const errStr:string = errStrings.find(es => error.message.includes(es)) const errStr: string = errStrings.find((es) => error.message.includes(es))
if (errStr) { if (errStr) {
fixes = fixesList[errStr] fixes = fixesList[errStr]
const cursorPosition: number = this.props.editorAPI.getHoverPosition({lineNumber: error.startLineNumber, column: error.startColumn}) const cursorPosition: number = this.props.editorAPI.getHoverPosition({
lineNumber: error.startLineNumber,
column: error.startColumn
})
const nodeAtPosition = await this.props.plugin.call('codeParser', 'definitionAtPosition', cursorPosition) const nodeAtPosition = await this.props.plugin.call('codeParser', 'definitionAtPosition', cursorPosition)
// Check if a function is hovered // Check if a function is hovered
if (nodeAtPosition && nodeAtPosition.nodeType === "FunctionDefinition") { if (nodeAtPosition && nodeAtPosition.nodeType === 'FunctionDefinition') {
// Identify type of AST node // Identify type of AST node
if (nodeAtPosition.parameters && !Array.isArray(nodeAtPosition.parameters) && Array.isArray(nodeAtPosition.parameters.parameters)) if (nodeAtPosition.parameters && !Array.isArray(nodeAtPosition.parameters) && Array.isArray(nodeAtPosition.parameters.parameters)) isOldAST = true
isOldAST = true
const paramNodes = isOldAST ? nodeAtPosition.parameters.parameters : nodeAtPosition.parameters const paramNodes = isOldAST ? nodeAtPosition.parameters.parameters : nodeAtPosition.parameters
for (const fix of fixes) { for (const fix of fixes) {
msg = paramNodes.length msg = paramNodes.length
? await this.fixForMethodWithParams(model, paramNodes, fix, error, isOldAST) ? await this.fixForMethodWithParams(model, paramNodes, fix, error, isOldAST)
: await this.fixForMethodWithoutParams(model, nodeAtPosition, fix, error, isOldAST) : await this.fixForMethodWithoutParams(model, nodeAtPosition, fix, error, isOldAST)
this.addQuickFix(actions, error, model.uri, {title: fix.title, range: fix.range, text: msg}) this.addQuickFix(actions, error, model.uri, {
id: fix.id,
title: fix.title,
range: fix.range,
text: msg
})
} }
} else { } else {
for (const fix of fixes) { for (const fix of fixes) {
if (fix && nodeAtPosition && fix.nodeType !== nodeAtPosition.nodeType) continue if (fix && nodeAtPosition && fix.nodeType && fix.nodeType !== nodeAtPosition.nodeType) continue
else this.addQuickFix(actions, error, model.uri, {title: fix.title, range: fix.range || error, text: fix.message}) switch (fix.id) {
case 2: {
// To add specific pragma based on error
const startIndex = error.message.indexOf('pragma')
const endIndex = error.message.indexOf(';')
const msg = error.message.substring(startIndex, endIndex + 1)
this.addQuickFix(actions, error, model.uri, {
title: fix.title,
range: fix.range,
text: msg
})
break
}
case 8: {
// To add `abstract` in the contract
const lineContent: string = model.getValueInRange(error)
this.addQuickFix(actions, error, model.uri, {
title: fix.title,
range: error,
text: fix.message + lineContent
})
break
}
case 9.1:
case 9.2:
case 10.1:
case 10.2:
case 10.3:
case 11.1:
case 11.2: {
// To add data location in constructor params, function params and variables
const lineContent: string = model.getValueInRange(error)
const words = lineContent.split(' ')
this.addQuickFix(actions, error, model.uri, {
title: fix.title,
range: error,
text: words[0] + fix.message + words[1]
})
break
}
default:
this.addQuickFix(actions, error, model.uri, {
title: fix.title,
range: fix.range || error,
text: fix.message
})
}
} }
} }
} }
@ -62,16 +115,17 @@ export class RemixCodeActionProvider implements monaco.languages.CodeActionProvi
* @param fix details of quick fix to apply * @param fix details of quick fix to apply
*/ */
addQuickFix(actions: monaco.languages.CodeAction[], error: monaco.editor.IMarkerData, uri: monaco.Uri, fix: Record<string, any>) { addQuickFix(actions: monaco.languages.CodeAction[], error: monaco.editor.IMarkerData, uri: monaco.Uri, fix: Record<string, any>) {
const {title, range, text} = fix const {id, title, range, text} = fix
actions.push({ actions.push({
title, title,
diagnostics: [error], diagnostics: [error],
kind: "quickfix", kind: 'quickfix',
edit: { edit: {
edits: [ edits: [
{ {
resource: uri, resource: uri,
edit: { range, text } textEdit: {range, text},
versionId: undefined
} }
] ]
}, },
@ -88,7 +142,13 @@ export class RemixCodeActionProvider implements monaco.languages.CodeActionProvi
* @param isOldAST true, if AST node contains legacy fields * @param isOldAST true, if AST node contains legacy fields
* @returns message to be placed as quick fix * @returns message to be placed as quick fix
*/ */
async fixForMethodWithParams(model: monaco.editor.ITextModel, paramNodes: Record<string, any>[], fix: Record<string, any>, error: monaco.editor.IMarkerData, isOldAST: boolean): Promise<string> { async fixForMethodWithParams(
model: monaco.editor.ITextModel,
paramNodes: Record<string, any>[],
fix: Record<string, any>,
error: monaco.editor.IMarkerData,
isOldAST: boolean
): Promise<string> {
let lastParamEndLoc: Record<string, any>, fixLineNumber: number, msg: string let lastParamEndLoc: Record<string, any>, fixLineNumber: number, msg: string
// Get last function parameter node // Get last function parameter node
const lastParamNode: Record<string, any> = paramNodes[paramNodes.length - 1] const lastParamNode: Record<string, any> = paramNodes[paramNodes.length - 1]
@ -103,12 +163,13 @@ export class RemixCodeActionProvider implements monaco.languages.CodeActionProvi
fixLineNumber = lastParamEndLoc.line fixLineNumber = lastParamEndLoc.line
} }
const lineContent: string = model.getLineContent(fixLineNumber) const lineContent: string = model.getLineContent(fixLineNumber)
if (fix.id === 5 && lineContent.includes(' view ')) if (fix.id === 5 && lineContent.includes(' view ')) msg = lineContent.replace('view', 'pure')
msg = lineContent.replace('view', 'pure') else if (isOldAST) msg = lineContent.substring(0, lastParamEndLoc.column + 2) + fix.message + lineContent.substring(lastParamEndLoc.column + 1, lineContent.length)
else if (isOldAST)
msg = lineContent.substring(0, lastParamEndLoc.column + 2) + fix.message + lineContent.substring(lastParamEndLoc.column + 1, lineContent.length)
else else
msg = lineContent.substring(0, lastParamEndLoc.column + lastParamNode.name.length + 2) + fix.message + lineContent.substring(lastParamEndLoc.column + lastParamNode.name.length + 1, lineContent.length) msg =
lineContent.substring(0, lastParamEndLoc.column + lastParamNode.name.length + 2) +
fix.message +
lineContent.substring(lastParamEndLoc.column + lastParamNode.name.length + 1, lineContent.length)
fix.range = { fix.range = {
startLineNumber: fixLineNumber, startLineNumber: fixLineNumber,
@ -128,7 +189,13 @@ export class RemixCodeActionProvider implements monaco.languages.CodeActionProvi
* @param isOldAST true, if AST node contains legacy fields * @param isOldAST true, if AST node contains legacy fields
* @returns message to be placed as quick fix * @returns message to be placed as quick fix
*/ */
async fixForMethodWithoutParams(model: monaco.editor.ITextModel, nodeAtPosition: Record<string, any>, fix: Record<string, any>, error: monaco.editor.IMarkerData, isOldAST: boolean): Promise<string> { async fixForMethodWithoutParams(
model: monaco.editor.ITextModel,
nodeAtPosition: Record<string, any>,
fix: Record<string, any>,
error: monaco.editor.IMarkerData,
isOldAST: boolean
): Promise<string> {
let fixLineNumber: number, msg: string let fixLineNumber: number, msg: string
if (isOldAST) { if (isOldAST) {
const location: Record<string, any> = await this.props.plugin.call('codeParser', 'getLineColumnOfNode', nodeAtPosition) const location: Record<string, any> = await this.props.plugin.call('codeParser', 'getLineColumnOfNode', nodeAtPosition)
@ -140,8 +207,7 @@ export class RemixCodeActionProvider implements monaco.languages.CodeActionProvi
if (fix.id === 5 && lineContent.includes(' view ')) { if (fix.id === 5 && lineContent.includes(' view ')) {
msg = lineContent.replace('view', 'pure') msg = lineContent.replace('view', 'pure')
} else } else msg = lineContent.substring(0, i + 3) + fix.message + lineContent.substring(i + 3, lineContent.length)
msg = lineContent.substring(0, i + 3) + fix.message + lineContent.substring(i + 3, lineContent.length)
fix.range = { fix.range = {
startLineNumber: fixLineNumber, startLineNumber: fixLineNumber,

@ -521,6 +521,20 @@ export function GetGlobalVariable(range: monacoTypes.IRange, monaco): monacoType
export function GetGlobalFunctions(range: monacoTypes.IRange, monaco): monacoTypes.languages.CompletionItem[] { export function GetGlobalFunctions(range: monacoTypes.IRange, monaco): monacoTypes.languages.CompletionItem[] {
return [ return [
{
label: 'fallback',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'fallback() ${1:external} ${2:payable} { }',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
range
},
{
label: 'receive',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'receive() ${1:external} ${2:payable} { }',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
range
},
{ {
detail: 'assert(bool condition): throws if the condition is not met - to be used for internal errors.', detail: 'assert(bool condition): throws if the condition is not met - to be used for internal errors.',
insertText: 'assert(${1:condition});', insertText: 'assert(${1:condition});',

@ -55,7 +55,6 @@ export default {
{ {
id: 2, id: 2,
title: 'Add Solidity pragma', title: 'Add Solidity pragma',
message: 'pragma solidity ^0.*.*;',
nodeType: 'PragmaDirective', nodeType: 'PragmaDirective',
range: { range: {
startLineNumber: 2, startLineNumber: 2,
@ -106,5 +105,86 @@ export default {
message: 'pure ', message: 'pure ',
nodeType: 'FunctionDefinition' nodeType: 'FunctionDefinition'
} }
],
'TypeError: Trying to override non-virtual function. Did you forget to add "virtual"':[
{
id: 6,
title: "Add 'virtual' specifier",
message: 'virtual',
nodeType: 'FunctionDefinition'
}
],
'TypeError: Overriding function is missing "override" specifier':[
{
id: 7,
title: "Add 'override' specifier",
message: 'override',
nodeType: 'FunctionDefinition'
}
],
'should be marked as abstract': [
{
id: 8,
title: "Add 'abstract' to contract",
message: 'abstract ',
nodeType: 'ContractDefinition'
}
],
'TypeError: Data location must be "storage" or "memory" for constructor parameter, but none was given.': [
{
id: 9.1,
title: "Add 'storage' to param",
message: ' storage '
},
{
id: 9.2,
title: "Add 'memory' to param",
message: ' memory '
}
],
'TypeError: Data location must be "storage", "memory" or "calldata" for variable, but none was given.': [
{
id: 10.1,
title: "Add 'storage' to variable",
message: ' storage '
},
{
id: 10.2,
title: "Add 'memory' to variable",
message: ' memory '
},
{
id: 10.3,
title: "Add 'calldata' to variable",
message: ' calldata '
}
],
'TypeError: Data location must be "memory" or "calldata" for parameter in function, but none was given.': [
{
id: 11.1,
title: "Add 'memory' to param",
message: ' memory '
},
{
id: 11.2,
title: "Add 'calldata' to param",
message: ' calldata '
}
],
'SyntaxError: No visibility specified. Did you intend to add "external': [
{
id: 12,
title: "Add visibility 'external'",
message: 'external ',
nodeType: 'FunctionDefinition'
}
],
'DeclarationError: Receive ether function must be payable, but is "nonpayable".': [
{
id: 13,
title: "Make function 'payable'",
message: 'payable ',
nodeType: 'FunctionDefinition'
}
] ]
} }

@ -1,9 +1,9 @@
.hover-row { .hover-row {
white-space: pre; white-space: pre;
margin-left : 10px;
background : var(--light); background : var(--light);
font-weight : bold; font-weight : bold;
font-family : monospace; font-family : monospace;
font-size: smaller;
padding : 10px; padding : 10px;
border-radius : 10px; border-radius : 10px;
height: auto; height: auto;
@ -26,3 +26,7 @@
filter: opacity(0.5); filter: opacity(0.5);
font-weight: bolder; font-weight: bolder;
} }
div.monaco-list-row > span.title {
margin-top: 12px;
}

@ -18,12 +18,13 @@ import {RemixDefinitionProvider} from './providers/definitionProvider'
import { RemixCodeActionProvider } from './providers/codeActionProvider' import { RemixCodeActionProvider } from './providers/codeActionProvider'
import './remix-ui-editor.css' import './remix-ui-editor.css'
import { circomLanguageConfig, circomTokensProvider } from './syntaxes/circom' import { circomLanguageConfig, circomTokensProvider } from './syntaxes/circom'
import { IPosition } from 'monaco-editor'
enum MarkerSeverity { enum MarkerSeverity {
Hint = 1, Hint = 1,
Info = 2, Info = 2,
Warning = 4, Warning = 4,
Error = 8 Error = 8,
} }
type sourceAnnotation = { type sourceAnnotation = {
@ -108,6 +109,7 @@ export type EditorAPIType = {
keepDecorationsFor: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn keepDecorationsFor: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn
addErrorMarker: (errors: errorMarker[], from: string) => void addErrorMarker: (errors: errorMarker[], from: string) => void
clearErrorMarkers: (sources: string[] | { [fileName: string]: any }, from: string) => void clearErrorMarkers: (sources: string[] | { [fileName: string]: any }, from: string) => void
getPositionAt: (offset: number) => monacoTypes.IPosition
} }
/* eslint-disable-next-line */ /* eslint-disable-next-line */
@ -151,6 +153,7 @@ export const EditorUI = (props: EditorUIProps) => {
const pasteCodeRef = useRef(false) const pasteCodeRef = useRef(false)
const editorRef = useRef(null) const editorRef = useRef(null)
const monacoRef = useRef<Monaco>(null) const monacoRef = useRef<Monaco>(null)
const currentFunction = useRef('')
const currentFileRef = useRef('') const currentFileRef = useRef('')
const currentUrlRef = useRef('') const currentUrlRef = useRef('')
// const currentDecorations = useRef({ sourceAnnotationsPerFile: {}, markerPerFile: {} }) // decorations that are currently in use by the editor // const currentDecorations = useRef({ sourceAnnotationsPerFile: {}, markerPerFile: {} }) // decorations that are currently in use by the editor
@ -274,7 +277,7 @@ export const EditorUI = (props: EditorUIProps) => {
// returns // returns
{ token: 'keyword.returns', foreground: greenColor }, { token: 'keyword.returns', foreground: greenColor },
{token: 'keyword.return', foreground: greenColor} { token: 'keyword.return', foreground: greenColor },
], ],
colors: { colors: {
// see https://code.visualstudio.com/api/references/theme-color for more settings // see https://code.visualstudio.com/api/references/theme-color for more settings
@ -284,7 +287,7 @@ export const EditorUI = (props: EditorUIProps) => {
'editorSuggestWidget.selectedForeground': textColor, 'editorSuggestWidget.selectedForeground': textColor,
'editorSuggestWidget.highlightForeground': primaryColor, 'editorSuggestWidget.highlightForeground': primaryColor,
'editorSuggestWidget.focusHighlightForeground': infoColor, 'editorSuggestWidget.focusHighlightForeground': infoColor,
'editor.lineHighlightBorder': secondaryColor, 'editor.lineHighlightBorder': textbackground,
'editor.lineHighlightBackground': textbackground === darkColor ? lightColor : secondaryColor, 'editor.lineHighlightBackground': textbackground === darkColor ? lightColor : secondaryColor,
'editorGutter.background': lightColor, 'editorGutter.background': lightColor,
//'editor.selectionHighlightBackground': secondaryColor, //'editor.selectionHighlightBackground': secondaryColor,
@ -293,8 +296,8 @@ export const EditorUI = (props: EditorUIProps) => {
'menu.background': textbackground, 'menu.background': textbackground,
'menu.selectionBackground': secondaryColor, 'menu.selectionBackground': secondaryColor,
'menu.selectionForeground': textColor, 'menu.selectionForeground': textColor,
'menu.selectionBorder': secondaryColor 'menu.selectionBorder': secondaryColor,
} },
}) })
monacoRef.current.editor.setTheme(themeName) monacoRef.current.editor.setTheme(themeName)
} }
@ -312,7 +315,7 @@ export const EditorUI = (props: EditorUIProps) => {
const file = editorModelsState[props.currentFile] const file = editorModelsState[props.currentFile]
editorRef.current.setModel(file.model) editorRef.current.setModel(file.model)
editorRef.current.updateOptions({ editorRef.current.updateOptions({
readOnly: editorModelsState[props.currentFile].readOnly readOnly: editorModelsState[props.currentFile].readOnly,
}) })
if (file.language === 'sol') { if (file.language === 'sol') {
monacoRef.current.editor.setModelLanguage(file.model, 'remix-solidity') monacoRef.current.editor.setModelLanguage(file.model, 'remix-solidity')
@ -336,10 +339,10 @@ export const EditorUI = (props: EditorUIProps) => {
options: { options: {
isWholeLine: false, isWholeLine: false,
glyphMarginHoverMessage: { glyphMarginHoverMessage: {
value: (decoration.from ? `from ${decoration.from}:\n` : '') + decoration.text value: (decoration.from ? `from ${decoration.from}:\n` : '') + decoration.text,
},
glyphMarginClassName: `fal fa-exclamation-square text-${decoration.type === 'error' ? 'danger' : decoration.type === 'warning' ? 'warning' : 'info'}`,
}, },
glyphMarginClassName: `fal fa-exclamation-square text-${decoration.type === 'error' ? 'danger' : decoration.type === 'warning' ? 'warning' : 'info'}`
}
} }
} }
if (typeOfDecoration === 'markerPerFile') { if (typeOfDecoration === 'markerPerFile') {
@ -362,8 +365,8 @@ export const EditorUI = (props: EditorUIProps) => {
), ),
options: { options: {
isWholeLine, isWholeLine,
inlineClassName: `${isWholeLine ? 'alert-info' : 'inline-class'} border-0 highlightLine${decoration.position.start.line + 1}` inlineClassName: `${isWholeLine ? 'alert-info' : 'inline-class'} border-0 highlightLine${decoration.position.start.line + 1}`,
} },
} }
} }
if (typeOfDecoration === 'lineTextPerFile') { if (typeOfDecoration === 'lineTextPerFile') {
@ -379,11 +382,11 @@ export const EditorUI = (props: EditorUIProps) => {
options: { options: {
after: { after: {
content: ` ${lineTextDecoration.content}`, content: ` ${lineTextDecoration.content}`,
inlineClassName: `${lineTextDecoration.className}` inlineClassName: `${lineTextDecoration.className}`,
}, },
afterContentClassName: `${lineTextDecoration.afterContentClassName}`, afterContentClassName: `${lineTextDecoration.afterContentClassName}`,
hoverMessage: lineTextDecoration.hoverMessage hoverMessage: lineTextDecoration.hoverMessage,
} },
} }
} }
if (typeOfDecoration === 'lineTextPerFile') { if (typeOfDecoration === 'lineTextPerFile') {
@ -399,11 +402,11 @@ export const EditorUI = (props: EditorUIProps) => {
options: { options: {
after: { after: {
content: ` ${lineTextDecoration.content}`, content: ` ${lineTextDecoration.content}`,
inlineClassName: `${lineTextDecoration.className}` inlineClassName: `${lineTextDecoration.className}`,
}, },
afterContentClassName: `${lineTextDecoration.afterContentClassName}`, afterContentClassName: `${lineTextDecoration.afterContentClassName}`,
hoverMessage: lineTextDecoration.hoverMessage hoverMessage: lineTextDecoration.hoverMessage,
} },
} }
} }
} }
@ -413,7 +416,7 @@ export const EditorUI = (props: EditorUIProps) => {
if (!model) if (!model)
return { return {
currentDecorations: [], currentDecorations: [],
registeredDecorations: [] registeredDecorations: [],
} }
const decorations = [] const decorations = []
const newRegisteredDecorations = [] const newRegisteredDecorations = []
@ -427,7 +430,7 @@ export const EditorUI = (props: EditorUIProps) => {
} }
return { return {
currentDecorations: model.deltaDecorations(currentDecorations, decorations), currentDecorations: model.deltaDecorations(currentDecorations, decorations),
registeredDecorations: newRegisteredDecorations registeredDecorations: newRegisteredDecorations,
} }
} }
@ -435,7 +438,7 @@ export const EditorUI = (props: EditorUIProps) => {
const model = editorModelsState[filePath]?.model const model = editorModelsState[filePath]?.model
if (!model) if (!model)
return { return {
currentDecorations: [] currentDecorations: [],
} }
const decorations = [] const decorations = []
if (registeredDecorations) { if (registeredDecorations) {
@ -446,7 +449,7 @@ export const EditorUI = (props: EditorUIProps) => {
} }
} }
return { return {
currentDecorations: model.deltaDecorations(currentDecorations, decorations) currentDecorations: model.deltaDecorations(currentDecorations, decorations),
} }
} }
@ -456,7 +459,7 @@ export const EditorUI = (props: EditorUIProps) => {
const monacoDecoration = convertToMonacoDecoration(decoration, typeOfDecoration) const monacoDecoration = convertToMonacoDecoration(decoration, typeOfDecoration)
return { return {
currentDecorations: model.deltaDecorations([], [monacoDecoration]), currentDecorations: model.deltaDecorations([], [monacoDecoration]),
registeredDecorations: [{value: decoration, type: typeOfDecoration}] registeredDecorations: [{ value: decoration, type: typeOfDecoration }],
} }
} }
@ -477,7 +480,7 @@ export const EditorUI = (props: EditorUIProps) => {
const errorServerityMap = { const errorServerityMap = {
error: MarkerSeverity.Error, error: MarkerSeverity.Error,
warning: MarkerSeverity.Warning, warning: MarkerSeverity.Warning,
info: MarkerSeverity.Info info: MarkerSeverity.Info,
} }
if (model) { if (model) {
const markerData: monacoTypes.editor.IMarkerData = { const markerData: monacoTypes.editor.IMarkerData = {
@ -486,7 +489,7 @@ export const EditorUI = (props: EditorUIProps) => {
startColumn: (error.position.start && error.position.start.column) || 0, startColumn: (error.position.start && error.position.start.column) || 0,
endLineNumber: (error.position.end && error.position.end.line) || 0, endLineNumber: (error.position.end && error.position.end.line) || 0,
endColumn: (error.position.end && error.position.end.column) || 0, endColumn: (error.position.end && error.position.end.column) || 0,
message: error.message message: error.message,
} }
if (!allMarkersPerfile[filePath]) { if (!allMarkersPerfile[filePath]) {
allMarkersPerfile[filePath] = [] allMarkersPerfile[filePath] = []
@ -548,7 +551,7 @@ export const EditorUI = (props: EditorUIProps) => {
props.editorAPI.getFontSize = () => { props.editorAPI.getFontSize = () => {
if (!editorRef.current) return if (!editorRef.current) return
return editorRef.current.getOption(43).fontSize return editorRef.current.getOption(51)
} }
;(window as any).addRemixBreakpoint = (position) => { ;(window as any).addRemixBreakpoint = (position) => {
// make it available from e2e testing... // make it available from e2e testing...
@ -571,9 +574,9 @@ export const EditorUI = (props: EditorUIProps) => {
range: new monacoRef.current.Range(position.lineNumber, 1, position.lineNumber, 1), range: new monacoRef.current.Range(position.lineNumber, 1, position.lineNumber, 1),
options: { options: {
isWholeLine: false, isWholeLine: false,
glyphMarginClassName: 'fas fa-circle text-info' glyphMarginClassName: 'fas fa-circle text-info',
} },
} },
] ]
) )
prevState[currentFile][position.lineNumber] = decorationIds[0] prevState[currentFile][position.lineNumber] = decorationIds[0]
@ -625,7 +628,7 @@ export const EditorUI = (props: EditorUIProps) => {
</div> </div>
</div> </div>
</div> </div>
) ),
} }
props.plugin.call('notification', 'alert', modalContent) props.plugin.call('notification', 'alert', modalContent)
pasteCodeRef.current = true pasteCodeRef.current = true
@ -634,10 +637,10 @@ export const EditorUI = (props: EditorUIProps) => {
// zoomin zoomout // zoomin zoomout
editor.addCommand(monacoRef.current.KeyMod.CtrlCmd | (monacoRef.current.KeyCode as any).US_EQUAL, () => { editor.addCommand(monacoRef.current.KeyMod.CtrlCmd | (monacoRef.current.KeyCode as any).US_EQUAL, () => {
editor.updateOptions({fontSize: editor.getOption(43).fontSize + 1}) editor.updateOptions({fontSize: editor.getOption(51) + 1})
}) })
editor.addCommand(monacoRef.current.KeyMod.CtrlCmd | (monacoRef.current.KeyCode as any).US_MINUS, () => { editor.addCommand(monacoRef.current.KeyMod.CtrlCmd | (monacoRef.current.KeyCode as any).US_MINUS, () => {
editor.updateOptions({fontSize: editor.getOption(43).fontSize - 1}) editor.updateOptions({fontSize: editor.getOption(51) - 1})
}) })
// add context menu items // add context menu items
@ -648,10 +651,10 @@ export const EditorUI = (props: EditorUIProps) => {
contextMenuGroupId: 'zooming', // create a new grouping contextMenuGroupId: 'zooming', // create a new grouping
keybindings: [ keybindings: [
// eslint-disable-next-line no-bitwise // eslint-disable-next-line no-bitwise
monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.Equal monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.Equal,
], ],
run: () => { run: () => {
editor.updateOptions({fontSize: editor.getOption(43).fontSize + 1}) editor.updateOptions({fontSize: editor.getOption(51) + 1})
} }
} }
const zoomOutAction = { const zoomOutAction = {
@ -661,10 +664,10 @@ export const EditorUI = (props: EditorUIProps) => {
contextMenuGroupId: 'zooming', // create a new grouping contextMenuGroupId: 'zooming', // create a new grouping
keybindings: [ keybindings: [
// eslint-disable-next-line no-bitwise // eslint-disable-next-line no-bitwise
monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.Minus monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.Minus,
], ],
run: () => { run: () => {
editor.updateOptions({fontSize: editor.getOption(43).fontSize - 1}) editor.updateOptions({fontSize: editor.getOption(51) - 1})
} }
} }
const formatAction = { const formatAction = {
@ -674,12 +677,48 @@ export const EditorUI = (props: EditorUIProps) => {
contextMenuGroupId: 'formatting', // create a new grouping contextMenuGroupId: 'formatting', // create a new grouping
keybindings: [ keybindings: [
// eslint-disable-next-line no-bitwise // eslint-disable-next-line no-bitwise
monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyF monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyF,
], ],
run: async () => { run: async () => {
const file = await props.plugin.call('fileManager', 'getCurrentFile') const file = await props.plugin.call('fileManager', 'getCurrentFile')
await props.plugin.call('codeFormatter', 'format', file) await props.plugin.call('codeFormatter', 'format', file)
},
} }
let gptGenerateDocumentationAction
const executeGptGenerateDocumentationAction = {
id: 'generateDocumentation',
label: 'Generate documentation for this function',
contextMenuOrder: 0, // choose the order
contextMenuGroupId: 'gtp', // create a new grouping
keybindings: [],
run: async () => {
const file = await props.plugin.call('fileManager', 'getCurrentFile')
const content = await props.plugin.call('fileManager', 'readFile', file)
const message = `
solidity code: ${content}
Generate the documentation for the function ${currentFunction.current} using the Doxygen style syntax
`
await props.plugin.call('openaigpt', 'message', message)
},
}
let gptExplainFunctionAction
const executegptExplainFunctionAction = {
id: 'explainFunction',
label: 'Explain this function',
contextMenuOrder: 1, // choose the order
contextMenuGroupId: 'gtp', // create a new grouping
keybindings: [],
run: async () => {
const file = await props.plugin.call('fileManager', 'getCurrentFile')
const content = await props.plugin.call('fileManager', 'readFile', file)
const message = `
solidity code: ${content}
Explain the function ${currentFunction.current}
`
await props.plugin.call('openaigpt', 'message', message)
},
} }
const freeFunctionCondition = editor.createContextKey('freeFunctionCondition', false) const freeFunctionCondition = editor.createContextKey('freeFunctionCondition', false)
@ -692,7 +731,7 @@ export const EditorUI = (props: EditorUIProps) => {
precondition: 'freeFunctionCondition', precondition: 'freeFunctionCondition',
keybindings: [ keybindings: [
// eslint-disable-next-line no-bitwise // eslint-disable-next-line no-bitwise
monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyR monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyR,
], ],
run: async () => { run: async () => {
const { nodesAtPosition } = await retrieveNodesAtPosition(props.editorAPI, props.plugin) const { nodesAtPosition } = await retrieveNodesAtPosition(props.editorAPI, props.plugin)
@ -708,12 +747,14 @@ export const EditorUI = (props: EditorUIProps) => {
} else { } else {
props.plugin.call('notification', 'toast', 'Please go to Remix settings and activate the code editor features or wait that the current editor context is loaded.') props.plugin.call('notification', 'toast', 'Please go to Remix settings and activate the code editor features or wait that the current editor context is loaded.')
} }
} },
} }
editor.addAction(formatAction) editor.addAction(formatAction)
editor.addAction(zoomOutAction) editor.addAction(zoomOutAction)
editor.addAction(zoominAction) editor.addAction(zoominAction)
freeFunctionAction = editor.addAction(executeFreeFunctionAction) freeFunctionAction = editor.addAction(executeFreeFunctionAction)
gptGenerateDocumentationAction = editor.addAction(executeGptGenerateDocumentationAction)
gptExplainFunctionAction = editor.addAction(executegptExplainFunctionAction)
// we have to add the command because the menu action isn't always available (see onContextMenuHandlerForFreeFunction) // we have to add the command because the menu action isn't always available (see onContextMenuHandlerForFreeFunction)
editor.addCommand(monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyR, () => executeFreeFunctionAction.run()) editor.addCommand(monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyR, () => executeFreeFunctionAction.run())
@ -725,6 +766,15 @@ export const EditorUI = (props: EditorUIProps) => {
freeFunctionAction.dispose() freeFunctionAction.dispose()
freeFunctionAction = null freeFunctionAction = null
} }
if (gptGenerateDocumentationAction) {
gptGenerateDocumentationAction.dispose()
gptGenerateDocumentationAction = null
}
if (gptExplainFunctionAction) {
gptExplainFunctionAction.dispose()
gptExplainFunctionAction = null
}
const file = await props.plugin.call('fileManager', 'getCurrentFile') const file = await props.plugin.call('fileManager', 'getCurrentFile')
if (!file.endsWith('.sol')) { if (!file.endsWith('.sol')) {
freeFunctionCondition.set(false) freeFunctionCondition.set(false)
@ -736,6 +786,14 @@ export const EditorUI = (props: EditorUIProps) => {
executeFreeFunctionAction.label = `Run the free function "${freeFunctionNode.name}" in the Remix VM` executeFreeFunctionAction.label = `Run the free function "${freeFunctionNode.name}" in the Remix VM`
freeFunctionAction = editor.addAction(executeFreeFunctionAction) freeFunctionAction = editor.addAction(executeFreeFunctionAction)
} }
const functionImpl = nodesAtPosition.find((node) => node.kind === 'function')
if (functionImpl) {
currentFunction.current = functionImpl.name
executeGptGenerateDocumentationAction.label = `Generate documentation for the function "${functionImpl.name}"`
gptGenerateDocumentationAction = editor.addAction(executeGptGenerateDocumentationAction)
executegptExplainFunctionAction.label = `Explain the function "${functionImpl.name}"`
gptExplainFunctionAction = editor.addAction(executegptExplainFunctionAction)
}
freeFunctionCondition.set(!!freeFunctionNode) freeFunctionCondition.set(!!freeFunctionNode)
} }
contextmenu._onContextMenu = (...args) => { contextmenu._onContextMenu = (...args) => {
@ -756,7 +814,7 @@ export const EditorUI = (props: EditorUIProps) => {
editor.revealRange(input.options.selection) editor.revealRange(input.options.selection)
editor.setPosition({ editor.setPosition({
column: input.options.selection.startColumn, column: input.options.selection.startColumn,
lineNumber: input.options.selection.startLineNumber lineNumber: input.options.selection.startLineNumber,
}) })
} }
} catch (e) { } catch (e) {
@ -816,7 +874,7 @@ export const EditorUI = (props: EditorUIProps) => {
beforeMount={handleEditorWillMount} beforeMount={handleEditorWillMount}
options={{ options={{
glyphMargin: true, glyphMargin: true,
readOnly: (!editorRef.current || !props.currentFile) && editorModelsState[props.currentFile]?.readOnly readOnly: (!editorRef.current || !props.currentFile) && editorModelsState[props.currentFile]?.readOnly,
}} }}
defaultValue={defaultEditorValue} defaultValue={defaultEditorValue}
/> />

File diff suppressed because it is too large Load Diff

@ -134,3 +134,11 @@ export const upgradeReportMsg = (report: LayoutCompatibilityReport) => (
<div className="pl-4 text-danger">{report.explain()}</div> <div className="pl-4 text-danger">{report.explain()}</div>
</div> </div>
) )
export function RenderIf({ condition, children }: { condition: boolean, children: JSX.Element }) {
return condition ? children : null
}
export function RenderIfNot({ condition, children }: { condition: boolean, children: JSX.Element }) {
return condition ? null : children
}

@ -73,7 +73,7 @@ function HomeTabFeaturedPlugins({plugin}: HomeTabFeaturedPluginsProps) {
_paq.push(['trackEvent', 'hometabActivate', 'userActivate', 'sourcify']) _paq.push(['trackEvent', 'hometabActivate', 'userActivate', 'sourcify'])
} }
const startCookbook = async () => { const startCookbook = async () => {
await plugin.appManager.activatePlugin(['cookbook.dev']) await plugin.appManager.activatePlugin(['cookbookdev'])
plugin.verticalIcons.select('cookbook.dev') plugin.verticalIcons.select('cookbook.dev')
_paq.push(['trackEvent', 'hometabActivate', 'userActivate', 'cookbook.dev']) _paq.push(['trackEvent', 'hometabActivate', 'userActivate', 'cookbook.dev'])
} }

@ -67,6 +67,21 @@ export const Renderer = ({message, opt = {}, plugin}: RendererProps) => {
} }
} }
const askGtp = async () => {
try {
const content = await plugin.call('fileManager', 'readFile', editorOptions.errFile)
const message = `
solidity code: ${content}
error message: ${messageText}
explain why the error occurred and how to fix it.
`
await plugin.call('openaigpt', 'message', message)
} catch (err) {
console.error('unable to askGtp')
console.error(err)
}
}
return ( return (
<> <>
{messageText && !close && ( {messageText && !close && (
@ -82,6 +97,7 @@ export const Renderer = ({message, opt = {}, plugin}: RendererProps) => {
<i className="fas fa-times"></i> <i className="fas fa-times"></i>
</div> </div>
<CopyToClipboard content={messageText} className={` p-0 m-0 far fa-copy ${classList}`} direction={'top'} /> <CopyToClipboard content={messageText} className={` p-0 m-0 far fa-copy ${classList}`} direction={'top'} />
<span onClick={() => { askGtp() }}>ASK GPT</span>
</div> </div>
)} )}
</> </>

@ -16,14 +16,14 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
content: string content: string
}>({ }>({
display: '', display: '',
content: '' content: '',
}) })
const [atAddressOptions, setAtAddressOptions] = useState<{ const [atAddressOptions, setAtAddressOptions] = useState<{
title: string | JSX.Element title: string | JSX.Element
disabled: boolean disabled: boolean
}>({ }>({
title: <FormattedMessage id="udapp.atAddressOptionsTitle1" />, title: <FormattedMessage id="udapp.atAddressOptionsTitle1" />,
disabled: true disabled: true,
}) })
const [loadedAddress, setLoadedAddress] = useState<string>('') const [loadedAddress, setLoadedAddress] = useState<string>('')
const [contractOptions, setContractOptions] = useState<{ const [contractOptions, setContractOptions] = useState<{
@ -31,7 +31,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
disabled: boolean disabled: boolean
}>({ }>({
title: <FormattedMessage id="udapp.contractOptionsTitle1" />, title: <FormattedMessage id="udapp.contractOptionsTitle1" />,
disabled: true disabled: true,
}) })
const [loadedContractData, setLoadedContractData] = useState<ContractData>(null) const [loadedContractData, setLoadedContractData] = useState<ContractData>(null)
const [constructorInterface, setConstructorInterface] = useState<FuncABI>(null) const [constructorInterface, setConstructorInterface] = useState<FuncABI>(null)
@ -50,7 +50,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
enableAtAddress(false) enableAtAddress(false)
setAbiLabel({ setAbiLabel({
display: 'none', display: 'none',
content: 'ABI file selected' content: 'ABI file selected',
}) })
}, []) }, [])
@ -71,19 +71,19 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
if (/.(.abi)$/.exec(currentFile) && '' !== atAddressValue.current.value) { if (/.(.abi)$/.exec(currentFile) && '' !== atAddressValue.current.value) {
setAbiLabel({ setAbiLabel({
display: 'block', display: 'block',
content: currentFile content: currentFile,
}) })
enableAtAddress(true) enableAtAddress(true)
} else if (isContractFile(currentFile)) { } else if (isContractFile(currentFile)) {
setAbiLabel({ setAbiLabel({
display: 'none', display: 'none',
content: '' content: '',
}) })
if (!currentContract) enableAtAddress(false) if (!currentContract) enableAtAddress(false)
} else { } else {
setAbiLabel({ setAbiLabel({
display: 'none', display: 'none',
content: '' content: '',
}) })
if (!currentContract) enableAtAddress(false) if (!currentContract) enableAtAddress(false)
} }
@ -150,7 +150,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
<span className="text-start"> <span className="text-start">
<FormattedMessage id="udapp.atAddressOptionsTitle2" values={{ br: <br /> }} /> <FormattedMessage id="udapp.atAddressOptionsTitle2" values={{ br: <br /> }} />
</span> </span>
) ),
}) })
} else { } else {
setAtAddressOptions({ setAtAddressOptions({
@ -161,7 +161,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
<span className="text-start"> <span className="text-start">
<FormattedMessage id="udapp.atAddressOptionsTitle4" values={{ br: <br /> }} /> <FormattedMessage id="udapp.atAddressOptionsTitle4" values={{ br: <br /> }} />
</span> </span>
) ),
}) })
} }
} }
@ -170,7 +170,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
if (enable) { if (enable) {
setContractOptions({ setContractOptions({
disabled: false, disabled: false,
title: <FormattedMessage id="udapp.contractOptionsTitle2" /> title: <FormattedMessage id="udapp.contractOptionsTitle2" />,
}) })
} else { } else {
setContractOptions({ setContractOptions({
@ -182,7 +182,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
<span className="text-start"> <span className="text-start">
<FormattedMessage id="udapp.contractOptionsTitle4" values={{ br: <br /> }} /> <FormattedMessage id="udapp.contractOptionsTitle4" values={{ br: <br /> }} />
</span> </span>
) ),
}) })
} }
} }
@ -289,7 +289,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
setCompilerName(contract.compilerName) setCompilerName(contract.compilerName)
setContractOptions({ setContractOptions({
disabled: false, disabled: false,
title: <FormattedMessage id="udapp.contractOptionsTitle2" /> title: <FormattedMessage id="udapp.contractOptionsTitle2" />,
}) })
} }
}) })
@ -297,7 +297,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
setCompilerName('') setCompilerName('')
setContractOptions({ setContractOptions({
title: <FormattedMessage id="udapp.contractOptionsTitle1" />, title: <FormattedMessage id="udapp.contractOptionsTitle1" />,
disabled: true disabled: true,
}) })
} }
} }
@ -323,7 +323,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
<a href="https://eips.ethereum.org/EIPS/eip-55" target="_blank" rel="noreferrer"> <a href="https://eips.ethereum.org/EIPS/eip-55" target="_blank" rel="noreferrer">
EIP-55 EIP-55
</a> </a>
) ),
}} }}
/> />
</span> </span>
@ -343,7 +343,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
<a href="https://eips.ethereum.org/EIPS/eip-170" target="_blank" rel="noreferrer"> <a href="https://eips.ethereum.org/EIPS/eip-170" target="_blank" rel="noreferrer">
eip-170 eip-170
</a> </a>
) ),
}} }}
/> />
</div> </div>
@ -358,7 +358,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
<a href="https://eips.ethereum.org/EIPS/eip-3860" target="_blank" rel="noreferrer"> <a href="https://eips.ethereum.org/EIPS/eip-3860" target="_blank" rel="noreferrer">
eip-3860 eip-3860
</a> </a>
) ),
}} }}
/> />
</div> </div>
@ -383,7 +383,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
<FormattedMessage <FormattedMessage
id="udapp.compiledBy" id="udapp.compiledBy"
values={{ values={{
compilerName: <span className="text-capitalize">{compilerName}</span> compilerName: <span className="text-capitalize">{compilerName}</span>,
}} }}
/> />
</label> </label>
@ -423,7 +423,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
disabled={contractOptions.disabled} disabled={contractOptions.disabled}
style={{ style={{
display: loadType === 'abi' && !isContractFile(currentFile) ? 'none' : 'block', display: loadType === 'abi' && !isContractFile(currentFile) ? 'none' : 'block',
pointerEvents: contractOptions.disabled ? 'none' : 'auto' pointerEvents: contractOptions.disabled ? 'none' : 'auto',
}} }}
> >
<option value="" disabled hidden> <option value="" disabled hidden>
@ -509,12 +509,12 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
<div className="pt-2 d-flex flex-column sudapp_button udapp_atAddressSect"> <div className="pt-2 d-flex flex-column sudapp_button udapp_atAddressSect">
<div className="d-flex flex-row"> <div className="d-flex flex-row">
<CustomTooltip placement={'top-end'} tooltipClasses="text-wrap text-left" tooltipId="runAndDeployAddresstooltip" tooltipText={atAddressOptions.title}> <CustomTooltip placement={'top-end'} tooltipClasses="text-wrap text-left" tooltipId="runAndDeployAddresstooltip" tooltipText={atAddressOptions.title}>
<div id="runAndDeployAtAdressButtonContainer" onClick={loadFromAddress} data-title={atAddressOptions.title}> <div id="runAndDeployAtAdressButtonContainer" data-title={atAddressOptions.title}>
<button <button
className="udapp_atAddress btn-sm py-2 btn-primary" className="udapp_atAddress btn-sm py-2 btn-primary"
id="runAndDeployAtAdressButton" id="runAndDeployAtAdressButton"
disabled={atAddressOptions.disabled} disabled={atAddressOptions.disabled}
style={{pointerEvents: 'none', border: 'none'}} style={{ border: 'none' }}
onClick={loadFromAddress} onClick={loadFromAddress}
data-title={atAddressOptions.title} data-title={atAddressOptions.title}
> >
@ -532,7 +532,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
ref={atAddressValue} ref={atAddressValue}
className={(!addressIsValid ? 'border border-danger' : 'border-0') + ' h-100 udapp_input udapp_ataddressinput ataddressinput form-control'} className={(!addressIsValid ? 'border border-danger' : 'border-0') + ' h-100 udapp_input udapp_ataddressinput ataddressinput form-control'}
placeholder={intl.formatMessage({ placeholder={intl.formatMessage({
id: 'udapp.loadContractFromAddress' id: 'udapp.loadContractFromAddress',
})} })}
onChange={atAddressChanged} onChange={atAddressChanged}
/> />

@ -34,7 +34,7 @@ export function InstanceContainerUI(props: InstanceContainerProps) {
tooltipId="deployAndRunClearInstancesTooltip" tooltipId="deployAndRunClearInstancesTooltip"
tooltipText={<FormattedMessage id="udapp.deployAndRunClearInstances" />} tooltipText={<FormattedMessage id="udapp.deployAndRunClearInstances" />}
> >
<i className="mr-2 udapp_icon far fa-trash-alt" data-id="deployAndRunClearInstances" onClick={clearInstance} aria-hidden="true"></i> <i className="mr-1 udapp_icon far fa-trash-alt" data-id="deployAndRunClearInstances" onClick={clearInstance} aria-hidden="true"></i>
</CustomTooltip> </CustomTooltip>
) : null} ) : null}
</div> </div>

@ -111,6 +111,10 @@
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
border-right: 0; border-right: 0;
} }
.udapp_atAddress:focus {
outline: none;
box-shadow: none;
}
.udapp_atAddressSect { .udapp_atAddressSect {
margin-top: 8px; margin-top: 8px;
height: 32px; height: 32px;

@ -515,7 +515,6 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
const currentFile = api.currentFile const currentFile = api.currentFile
if (!isSolFileSelected()) return if (!isSolFileSelected()) return
_setCompilerVersionFromPragma(currentFile) _setCompilerVersionFromPragma(currentFile)
let externalCompType let externalCompType
if (hhCompilation) externalCompType = 'hardhat' if (hhCompilation) externalCompType = 'hardhat'
@ -527,7 +526,6 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
const currentFile = api.currentFile const currentFile = api.currentFile
if (!isSolFileSelected()) return if (!isSolFileSelected()) return
_setCompilerVersionFromPragma(currentFile) _setCompilerVersionFromPragma(currentFile)
let externalCompType let externalCompType
if (hhCompilation) externalCompType = 'hardhat' if (hhCompilation) externalCompType = 'hardhat'

@ -285,7 +285,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => {
const file = split[2] const file = split[2]
const parsedLocation = { const parsedLocation = {
start: parseInt(split[0]), start: parseInt(split[0]),
length: parseInt(split[1]) length: parseInt(split[1]),
} }
const locationToHighlight = testTab.offsetToLineColumnConverter.offsetToLineColumnWithContent(parsedLocation, parseInt(file), filesContent[fileName].content) const locationToHighlight = testTab.offsetToLineColumnConverter.offsetToLineColumnWithContent(parsedLocation, parseInt(file), filesContent[fileName].content)
await testTab.call('editor', 'discardHighlight') await testTab.call('editor', 'discardHighlight')
@ -549,7 +549,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => {
passed: result.totalPassing, passed: result.totalPassing,
failed: result.totalFailing, failed: result.totalFailing,
timeTaken: totalTime, timeTaken: totalTime,
rendered: false rendered: false,
} }
testsResultByFilename[filename]['summary'] = testsSummary testsResultByFilename[filename]['summary'] = testsSummary
showTestsResult() showTestsResult()
@ -597,7 +597,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => {
evmVersion, evmVersion,
optimize, optimize,
usingWorker: canUseWorker(currentVersion), usingWorker: canUseWorker(currentVersion),
runs runs,
} }
const deployCb = async (file: string, contractAddress: string) => { const deployCb = async (file: string, contractAddress: string) => {
const compilerData = await testTab.call('compilerArtefacts', 'getCompilerAbstract', file) const compilerData = await testTab.call('compilerArtefacts', 'getCompilerAbstract', file)
@ -838,35 +838,45 @@ export const SolidityUnitTesting = (props: Record<string, any>) => {
</button> </button>
</CustomTooltip> </CustomTooltip>
</div> </div>
<div className="d-flex align-items-center mx-3 pb-2 mt-2 border-bottom"> <div className="d-flex align-items-center ml-1 mr-3 pl-1 pb-2 mt-2 border-bottom custom-control custom-checkbox">
<input <input
id="checkAllTests" id="checkAllTests"
className="custom-control-input"
type="checkbox" type="checkbox"
data-id="testTabCheckAllTests"
onClick={checkAll} onClick={checkAll}
checked={checkSelectAll} checked={checkSelectAll}
onChange={() => {}} // eslint-disable-line onChange={() => {}} // eslint-disable-line
/> />
<label className="text-nowrap pl-2 mb-0" htmlFor="checkAllTests"> <label
data-id="testTabCheckAllTests"
htmlFor="checkAllTests"
className="form-check-label mb-0 ml-4 custom-control-label text-nowrap"
style={{ paddingTop: '0.125rem' }}
>
{' '} {' '}
<FormattedMessage id="solidityUnitTesting.selectAll" />{' '} <FormattedMessage id="solidityUnitTesting.selectAll" />{' '}
</label> </label>
</div> </div>
<div className="testList py-2 mt-0 border-bottom"> <div className="testList ml-1 pr-2 mt-0 border-bottom py-2">
{testFiles.length {testFiles.length
? testFiles.map((testFileObj: TestObject, index) => { ? testFiles.map((testFileObj: TestObject, index) => {
const elemId = `singleTest${testFileObj.fileName}` const elemId = `singleTest${testFileObj.fileName}`
return ( return (
<div className="d-flex align-items-center py-1" key={index}> <div className="d-flex align-items-center pl-1 custom-control custom-checkbox" key={index}>
<input <input
data-id="singleTest" className="singleTest custom-control-input"
className="singleTest"
id={elemId} id={elemId}
onChange={(e) => toggleCheckbox(e.target.checked, index)} onChange={(e) => toggleCheckbox(e.target.checked, index)}
type="checkbox" type="checkbox"
checked={testFileObj.checked} checked={testFileObj.checked}
/> />
<label className="singleTestLabel text-nowrap pl-2 mb-0" htmlFor={elemId}> <label
data-id="singleTest"
id={"id" + elemId}
className="singleTestLabel text-nowrap mb-0 form-check-label ml-4 custom-control-label text-nowrap"
htmlFor={elemId}
style={{ paddingTop: '0.125rem' }}
>
{testFileObj.fileName} {testFileObj.fileName}
</label> </label>
</div> </div>

@ -167,7 +167,7 @@ export const TabsUI = (props: TabsUIProps) => {
<button <button
data-id="play-editor" data-id="play-editor"
className="btn text-success py-0" className="btn text-success py-0"
disabled={!(tabsState.currentExt === 'js' || tabsState.currentExt === 'ts' || tabsState.currentExt === 'sol')} disabled={!(tabsState.currentExt === 'js' || tabsState.currentExt === 'ts' || tabsState.currentExt === 'sol' || tabsState.currentExt === 'circom')}
onClick={async () => { onClick={async () => {
const path = active().substr(active().indexOf('/') + 1, active().length) const path = active().substr(active().indexOf('/') + 1, active().length)
const content = await props.plugin.call('fileManager', 'readFile', path) const content = await props.plugin.call('fileManager', 'readFile', path)

@ -1,4 +1,4 @@
import { CLEAR_CONSOLE, CMD_HISTORY, EMPTY_BLOCK, ERROR, HTML, INFO, KNOWN_TRANSACTION, LISTEN_ON_NETWORK, LOG, NEW_TRANSACTION, SCRIPT, UNKNOWN_TRANSACTION, WARN } from '../types/terminalTypes' import { CLEAR_CONSOLE, CMD_HISTORY, EMPTY_BLOCK, ERROR, HTML, INFO, KNOWN_TRANSACTION, LISTEN_ON_NETWORK, LOG, TYPEWRITERLOG, TYPEWRITERWARNING, TYPEWRITERSUCCESS, NEW_TRANSACTION, SCRIPT, UNKNOWN_TRANSACTION, WARN } from '../types/terminalTypes'
export const initialState = { export const initialState = {
journalBlocks: [ journalBlocks: [
@ -151,6 +151,21 @@ export const registerScriptRunnerReducer = (state, action) => {
...state, ...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-log', provider: action.payload.provider }) journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-log', provider: action.payload.provider })
} }
case TYPEWRITERLOG:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, typewriter: true, style: 'text-log', provider: action.payload.provider })
}
case TYPEWRITERWARNING:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, typewriter: true, style: 'text-warning', provider: action.payload.provider })
}
case TYPEWRITERSUCCESS:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, typewriter: true, style: 'text-success', provider: action.payload.provider })
}
case INFO: case INFO:
return { return {
...state, ...state,

@ -8,7 +8,7 @@ import {
registerErrorScriptRunnerAction, registerErrorScriptRunnerAction,
registerWarnScriptRunnerAction, registerWarnScriptRunnerAction,
listenOnNetworkAction, listenOnNetworkAction,
initListeningOnNetwork initListeningOnNetwork,
} from './actions/terminalAction' } from './actions/terminalAction'
import { initialState, registerCommandReducer, addCommandHistoryReducer, registerScriptRunnerReducer } from './reducers/terminalReducer' import { initialState, registerCommandReducer, addCommandHistoryReducer, registerScriptRunnerReducer } from './reducers/terminalReducer'
import { getKeyOf, getValueOf, Objectfilter, matched } from './utils/utils' import { getKeyOf, getValueOf, Objectfilter, matched } from './utils/utils'
@ -45,7 +45,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const [toaster, setToaster] = useState(false) const [toaster, setToaster] = useState(false)
const [toastProvider, setToastProvider] = useState({ const [toastProvider, setToastProvider] = useState({
show: false, show: false,
fileName: '' fileName: '',
}) })
const [modalState, setModalState] = useState({ const [modalState, setModalState] = useState({
message: '', message: '',
@ -54,7 +54,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
cancelLabel: '', cancelLabel: '',
hide: true, hide: true,
cancelFn: () => {}, cancelFn: () => {},
handleHide: () => {} handleHide: () => {},
}) })
const [clearConsole, setClearConsole] = useState(false) const [clearConsole, setClearConsole] = useState(false)
@ -63,7 +63,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const [autoCompletState, setAutoCompleteState] = useState({ const [autoCompletState, setAutoCompleteState] = useState({
activeSuggestion: 0, activeSuggestion: 0,
data: { data: {
_options: [] _options: [],
}, },
_startingElement: 0, _startingElement: 0,
autoCompleteSelectedItem: {}, autoCompleteSelectedItem: {},
@ -75,7 +75,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
text: '', text: '',
userInput: '', userInput: '',
extraCommands: [], extraCommands: [],
commandHistoryIndex: 0 commandHistoryIndex: 0,
}) })
const [searchInput, setSearchInput] = useState('') const [searchInput, setSearchInput] = useState('')
@ -84,6 +84,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
// terminal inputRef // terminal inputRef
const inputEl = useRef(null) const inputEl = useRef(null)
const messagesEndRef = useRef(null) const messagesEndRef = useRef(null)
const typeWriterIndexes = useRef([])
// terminal dragable // terminal dragable
const panelRef = useRef(null) const panelRef = useRef(null)
@ -101,8 +102,8 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
scriptRunnerDispatch({ scriptRunnerDispatch({
type: 'html', type: 'html',
payload: { payload: {
message: [html ? (html.innerText ? html.innerText : html) : null] message: [html ? (html.innerText ? html.innerText : html) : null],
} },
}) })
}, },
@ -110,14 +111,14 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
if (typeof message === 'string') { if (typeof message === 'string') {
message = { message = {
value: message, value: message,
type: 'log' type: 'log',
} }
} }
scriptRunnerDispatch({ scriptRunnerDispatch({
type: message.type ? message.type : 'log', type: message.type ? message.type : 'log',
payload: {message: [message.value]} payload: { message: [message.value] },
}) })
} },
}) })
}, []) }, [])
@ -213,8 +214,8 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}, },
execute: (fileName, callback) => { execute: (fileName, callback) => {
return execute(fileName, callback) return execute(fileName, callback)
} },
} },
} }
try { try {
const cmds = vm.createContext(context) const cmds = vm.createContext(context)
@ -247,7 +248,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
// backspace or any key that should remove the autocompletion // backspace or any key that should remove the autocompletion
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
showSuggestions: false showSuggestions: false,
})) }))
} }
if (autoCompletState.showSuggestions && (event.which === 13 || event.which === 9)) { if (autoCompletState.showSuggestions && (event.which === 13 || event.which === 9)) {
@ -256,7 +257,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
...prevState, ...prevState,
activeSuggestion: 0, activeSuggestion: 0,
showSuggestions: false, showSuggestions: false,
userInput: Object.keys(autoCompletState.data._options[0]).toString() userInput: Object.keys(autoCompletState.data._options[0]).toString(),
})) }))
} else { } else {
if (autoCompletState.showSuggestions && (event.which === 13 || event.which === 9)) { if (autoCompletState.showSuggestions && (event.which === 13 || event.which === 9)) {
@ -266,14 +267,14 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
showSuggestions: false, showSuggestions: false,
userInput: autoCompletState.data._options[autoCompletState.activeSuggestion] userInput: autoCompletState.data._options[autoCompletState.activeSuggestion]
? Object.keys(autoCompletState.data._options[autoCompletState.activeSuggestion]).toString() ? Object.keys(autoCompletState.data._options[autoCompletState.activeSuggestion]).toString()
: inputEl.current.value : inputEl.current.value,
})) }))
} else { } else {
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
activeSuggestion: 0, activeSuggestion: 0,
showSuggestions: false, showSuggestions: false,
userInput: autoCompletState.data._options.length === 1 ? Object.keys(autoCompletState.data._options[0]).toString() : inputEl.current.value userInput: autoCompletState.data._options.length === 1 ? Object.keys(autoCompletState.data._options[0]).toString() : inputEl.current.value,
})) }))
} }
} }
@ -298,14 +299,14 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
inputEl.current.focus() inputEl.current.focus()
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
showSuggestions: false showSuggestions: false,
})) }))
} }
} else if (newstate._commandHistory.length && event.which === 38 && !autoCompletState.showSuggestions && autoCompletState.userInput === '') { } else if (newstate._commandHistory.length && event.which === 38 && !autoCompletState.showSuggestions && autoCompletState.userInput === '') {
event.preventDefault() event.preventDefault()
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
userInput: newstate._commandHistory[0] userInput: newstate._commandHistory[0],
})) }))
} else if (event.which === 38 && autoCompletState.showSuggestions) { } else if (event.which === 38 && autoCompletState.showSuggestions) {
event.preventDefault() event.preventDefault()
@ -315,7 +316,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
activeSuggestion: suggestionCount - 1, activeSuggestion: suggestionCount - 1,
userInput: Object.keys(autoCompletState.data._options[autoCompletState.activeSuggestion]).toString() userInput: Object.keys(autoCompletState.data._options[autoCompletState.activeSuggestion]).toString(),
})) }))
} else if (event.which === 38 && !autoCompletState.showSuggestions) { } else if (event.which === 38 && !autoCompletState.showSuggestions) {
// <arrowUp> // <arrowUp>
@ -332,7 +333,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
activeSuggestion: suggestionCount + 1, activeSuggestion: suggestionCount + 1,
userInput: Object.keys(autoCompletState.data._options[autoCompletState.activeSuggestion + 1]).toString() userInput: Object.keys(autoCompletState.data._options[autoCompletState.activeSuggestion + 1]).toString(),
})) }))
} else if (event.which === 40 && !autoCompletState.showSuggestions) { } else if (event.which === 40 && !autoCompletState.showSuggestions) {
if (_cmdIndex > -1) { if (_cmdIndex > -1) {
@ -359,7 +360,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
log: 'text-log', log: 'text-log',
info: 'text-log', info: 'text-log',
warn: 'text-warning', warn: 'text-warning',
error: 'text-danger' error: 'text-danger',
}[mode] // defaults }[mode] // defaults
if (mode) { if (mode) {
@ -389,6 +390,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const handleClearConsole = () => { const handleClearConsole = () => {
setClearConsole(true) setClearConsole(true)
typeWriterIndexes.current = []
dispatch({ type: 'clearconsole', payload: [] }) dispatch({ type: 'clearconsole', payload: [] })
inputEl.current.focus() inputEl.current.focus()
} }
@ -408,42 +410,42 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
showSuggestions: false, showSuggestions: false,
userInput: inputString userInput: inputString,
})) }))
} else { } else {
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
showSuggestions: true, showSuggestions: true,
userInput: inputString userInput: inputString,
})) }))
} }
const textList = inputString.split('.') const textList = inputString.split('.')
if (textList.length === 1) { if (textList.length === 1) {
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
data: {_options: []} data: { _options: [] },
})) }))
const result = Objectfilter(allPrograms, autoCompletState.userInput) const result = Objectfilter(allPrograms, autoCompletState.userInput)
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
data: {_options: result} data: { _options: result },
})) }))
} else { } else {
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
data: {_options: []} data: { _options: [] },
})) }))
const result = Objectfilter(allCommands, autoCompletState.userInput) const result = Objectfilter(allCommands, autoCompletState.userInput)
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
data: {_options: result} data: { _options: result },
})) }))
} }
} else { } else {
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
showSuggestions: false, showSuggestions: false,
userInput: inputString userInput: inputString,
})) }))
} }
} }
@ -453,7 +455,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
showSuggestions: false, showSuggestions: false,
userInput: result userInput: result,
})) }))
inputEl.current.focus() inputEl.current.focus()
} }
@ -466,7 +468,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
} }
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
activeSuggestion: suggestionCount - 1 activeSuggestion: suggestionCount - 1,
})) }))
} else if (event.keyCode === 40) { } else if (event.keyCode === 40) {
if (autoCompletState.activeSuggestion - 1 === autoCompletState.data._options.length) { if (autoCompletState.activeSuggestion - 1 === autoCompletState.data._options.length) {
@ -474,7 +476,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
} }
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
activeSuggestion: suggestionCount + 1 activeSuggestion: suggestionCount + 1,
})) }))
} }
} }
@ -488,7 +490,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
okFn, okFn,
cancelLabel, cancelLabel,
cancelFn, cancelFn,
hide hide,
})) }))
} }
@ -515,7 +517,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
display: display:
autoCompletState.showSuggestions && autoCompletState.userInput !== '' && autoCompletState.userInput.length > 0 && autoCompletState.data._options.length > 0 autoCompletState.showSuggestions && autoCompletState.userInput !== '' && autoCompletState.userInput.length > 0 && autoCompletState.data._options.length > 0
? 'block' ? 'block'
: 'none' : 'none',
}} }}
> >
<div> <div>
@ -545,7 +547,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
setAutoCompleteState((prevState) => ({ setAutoCompleteState((prevState) => ({
...prevState, ...prevState,
activeSuggestion: 0, activeSuggestion: 0,
showSuggestions: false showSuggestions: false,
})) }))
} }
@ -590,12 +592,17 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
<CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText="Pending Transactions"> <CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText="Pending Transactions">
<div className="mx-2">0</div> <div className="mx-2">0</div>
</CustomTooltip> </CustomTooltip>
<div className="pt-1 h-80 mx-3 align-items-center remix_ui_terminal_listenOnNetwork custom-control custom-checkbox"> <div className="h-80 mx-3 align-items-center remix_ui_terminal_listenOnNetwork custom-control custom-checkbox">
<CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText={intl.formatMessage({ id: 'terminal.listenTitle' })}> <CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText={intl.formatMessage({ id: 'terminal.listenTitle' })}>
<input className="custom-control-input" id="listenNetworkCheck" onChange={listenOnNetwork} type="checkbox" /> <input className="custom-control-input" id="listenNetworkCheck" onChange={listenOnNetwork} type="checkbox" />
</CustomTooltip> </CustomTooltip>
<CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText={intl.formatMessage({ id: 'terminal.listenTitle' })}> <CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText={intl.formatMessage({ id: 'terminal.listenTitle' })}>
<label className="pt-1 form-check-label custom-control-label text-nowrap" htmlFor="listenNetworkCheck" data-id="listenNetworkCheckInput"> <label
className="form-check-label custom-control-label text-nowrap"
style={{ paddingTop: '0.125rem' }}
htmlFor="listenNetworkCheck"
data-id="listenNetworkCheckInput"
>
<FormattedMessage id="terminal.listen" /> <FormattedMessage id="terminal.listen" />
</label> </label>
</CustomTooltip> </CustomTooltip>
@ -686,7 +693,11 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}) })
} else if (Array.isArray(x.message)) { } else if (Array.isArray(x.message)) {
return x.message.map((msg, i) => { return x.message.map((msg, i) => {
if (!msg) msg = 'null' // strictly check condition on 0, false, except undefined, NaN.
// if you type `undefined`, terminal automatically throws error, it's error message: "undefined" is not valid JSON
// if you type `NaN`, terminal would give `null`
if (msg === false || msg === 0) msg = msg.toString()
else if (!msg) msg = 'null'
if (React.isValidElement(msg)) { if (React.isValidElement(msg)) {
return ( return (
<div className="px-4 block" data-id="block" key={i}> <div className="px-4 block" data-id="block" key={i}>
@ -714,23 +725,38 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
</div> </div>
) )
} else { } else {
// typeWriterIndexes: we don't want to rerender using typewriter when the react component updates
if (x.typewriter && !typeWriterIndexes.current.includes(index)) {
typeWriterIndexes.current.push(index)
return ( return (
<div className={classNameBlock} data-id="block" key={i}> <div className={classNameBlock} data-id="block" key={index}> <span ref={(element) => {
<span className={x.style}>{msg ? msg.toString() : null}</span> typewrite(element, msg ? msg.toString() : null)
</div> }} className={x.style}></span></div>
)
} else {
return (
<div className={classNameBlock} data-id="block" key={i}><span className={x.style}>{msg ? msg.toString() : null}</span></div>
) )
} }
}
}) })
} else {
// typeWriterIndexes: we don't want to rerender using typewriter when the react component updates
if (x.typewriter && !typeWriterIndexes.current.includes(index)) {
typeWriterIndexes.current.push(index)
return (
<div className={classNameBlock} data-id="block" key={index}> <span ref={(element) => {
typewrite(element, x.message)
}} className={x.style}></span></div>
)
} else { } else {
if (typeof x.message !== 'function') { if (typeof x.message !== 'function') {
return ( return (
<div className={classNameBlock} data-id="block" key={index}> <div className={classNameBlock} data-id="block" key={index}> <span className={x.style}> {x.message}</span></div>
{' '}
<span className={x.style}> {x.message}</span>
</div>
) )
} }
} }
}
})} })}
<div ref={messagesEndRef} /> <div ref={messagesEndRef} />
</div> </div>
@ -769,6 +795,17 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
) )
} }
const typewrite = (elementsRef, message) => {
(() => {
let count = 0
const id = setInterval(() => {
count++
elementsRef.innerText = message.substr(0, count)
if (message === count) clearInterval(id)
}, 5)
})()
}
function isHtml (value) { function isHtml (value) {
if (!value.indexOf) return false if (!value.indexOf) return false
return value.indexOf('<div') !== -1 || value.indexOf('<span') !== -1 || value.indexOf('<p') !== -1 || value.indexOf('<label') !== -1 || value.indexOf('<b') !== -1 return value.indexOf('<div') !== -1 || value.indexOf('<span') !== -1 || value.indexOf('<p') !== -1 || value.indexOf('<label') !== -1 || value.indexOf('<b') !== -1

@ -15,6 +15,9 @@ export const NEW_CALL = 'newCall'
export const HTML = 'html' export const HTML = 'html'
export const LOG = 'log' export const LOG = 'log'
export const TYPEWRITERLOG = 'typewriterlog'
export const TYPEWRITERWARNING = 'typewriterwarning'
export const TYPEWRITERSUCCESS = 'typewritersuccess'
export const INFO = 'info' export const INFO = 'info'
export const WARN = 'warn' export const WARN = 'warn'
export const ERROR = 'error' export const ERROR = 'error'

@ -81,7 +81,7 @@ urlResolver.resolve(fileName, urlHandler)
Please feel free to open an issue or a pull request. 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 ### License
MIT © 2018-21 Remix Team MIT © 2018-21 Remix Team

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-url-resolver", "name": "@remix-project/remix-url-resolver",
"version": "0.0.60", "version": "0.0.61",
"description": "Solidity import url resolver engine", "description": "Solidity import url resolver engine",
"main": "src/index.js", "main": "src/index.js",
"types": "src/index.d.ts", "types": "src/index.d.ts",
@ -40,5 +40,5 @@
"typescript": "^3.1.6" "typescript": "^3.1.6"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "b11b11623729f741a5ccd387bc60dc5db41f28ab" "gitHead": "335beb044cbd9d58c255bd8441a310757c99bf40"
} }

@ -14,7 +14,7 @@
Please feel free to open an issue or a pull request. 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 ### License
MIT © 2022 Remix Team MIT © 2022 Remix Team

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-ws-templates", "name": "@remix-project/remix-ws-templates",
"version": "1.0.25", "version": "1.0.26",
"description": "Create a Remix IDE workspace using different templates", "description": "Create a Remix IDE workspace using different templates",
"main": "src/index.js", "main": "src/index.js",
"types": "src/index.d.ts", "types": "src/index.d.ts",
@ -24,5 +24,5 @@
"ethers": "^5.4.2", "ethers": "^5.4.2",
"web3": "^4.1.1" "web3": "^4.1.1"
}, },
"gitHead": "b11b11623729f741a5ccd387bc60dc5db41f28ab" "gitHead": "335beb044cbd9d58c255bd8441a310757c99bf40"
} }

@ -1,8 +1,7 @@
import { ethers } from 'ethers' import { ethers } from 'ethers'
// https://etherscan.io/address/0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2#code // https://etherscan.io/address/0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2#code
export const CREATE2_DEPLOYER_ADDRESS = export const CREATE2_DEPLOYER_ADDRESS = '0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2'
"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2";
/** /**
* Deploy the given contract using a factory * Deploy the given contract using a factory
@ -14,13 +13,12 @@ export const CREATE2_DEPLOYER_ADDRESS =
* @return {string} deployed contract address * @return {string} deployed contract address
*/ */
export const deploy = async (contractName: string, args: Array<any>, salt: string, accountIndex?: number): Promise<string> => { export const deploy = async (contractName: string, args: Array<any>, salt: string, accountIndex?: number): Promise<string> => {
console.log(`deploying ${contractName}`) console.log(`deploying ${contractName}`)
const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner(accountIndex) const signer = new ethers.providers.Web3Provider(web3Provider).getSigner(accountIndex)
const factory = new ethers.Contract(CREATE2_DEPLOYER_ADDRESS, contractDeployerAbi, signer);
const factory = new ethers.Contract(CREATE2_DEPLOYER_ADDRESS, contractDeployerAbi, signer)
//@ts-ignore
const contract = await ethers.getContractFactory(contractName) const contract = await ethers.getContractFactory(contractName)
const initCode = contract.getDeployTransaction(args) const initCode = contract.getDeployTransaction(args)
@ -40,219 +38,219 @@ export const deploy = async (contractName: string, args: Array<any>, salt: strin
export const contractDeployerAbi = [ export const contractDeployerAbi = [
{ {
"anonymous": false, anonymous: false,
"inputs": [ inputs: [
{ {
"indexed": true, indexed: true,
"internalType": "address", internalType: 'address',
"name": "previousOwner", name: 'previousOwner',
"type": "address" type: 'address',
}, },
{ {
"indexed": true, indexed: true,
"internalType": "address", internalType: 'address',
"name": "newOwner", name: 'newOwner',
"type": "address" type: 'address',
} },
], ],
"name": "OwnershipTransferred", name: 'OwnershipTransferred',
"type": "event" type: 'event',
}, },
{ {
"anonymous": false, anonymous: false,
"inputs": [ inputs: [
{ {
"indexed": false, indexed: false,
"internalType": "address", internalType: 'address',
"name": "account", name: 'account',
"type": "address" type: 'address',
} },
], ],
"name": "Paused", name: 'Paused',
"type": "event" type: 'event',
}, },
{ {
"anonymous": false, anonymous: false,
"inputs": [ inputs: [
{ {
"indexed": false, indexed: false,
"internalType": "address", internalType: 'address',
"name": "account", name: 'account',
"type": "address" type: 'address',
} },
], ],
"name": "Unpaused", name: 'Unpaused',
"type": "event" type: 'event',
}, },
{ {
"inputs": [ inputs: [
{ {
"internalType": "bytes32", internalType: 'bytes32',
"name": "salt", name: 'salt',
"type": "bytes32" type: 'bytes32',
}, },
{ {
"internalType": "bytes32", internalType: 'bytes32',
"name": "codeHash", name: 'codeHash',
"type": "bytes32" type: 'bytes32',
} },
], ],
"name": "computeAddress", name: 'computeAddress',
"outputs": [ outputs: [
{ {
"internalType": "address", internalType: 'address',
"name": "", name: '',
"type": "address" type: 'address',
} },
], ],
"stateMutability": "view", stateMutability: 'view',
"type": "function" type: 'function',
}, },
{ {
"inputs": [ inputs: [
{ {
"internalType": "bytes32", internalType: 'bytes32',
"name": "salt", name: 'salt',
"type": "bytes32" type: 'bytes32',
}, },
{ {
"internalType": "bytes32", internalType: 'bytes32',
"name": "codeHash", name: 'codeHash',
"type": "bytes32" type: 'bytes32',
}, },
{ {
"internalType": "address", internalType: 'address',
"name": "deployer", name: 'deployer',
"type": "address" type: 'address',
} },
], ],
"name": "computeAddressWithDeployer", name: 'computeAddressWithDeployer',
"outputs": [ outputs: [
{ {
"internalType": "address", internalType: 'address',
"name": "", name: '',
"type": "address" type: 'address',
} },
], ],
"stateMutability": "pure", stateMutability: 'pure',
"type": "function" type: 'function',
}, },
{ {
"inputs": [ inputs: [
{ {
"internalType": "uint256", internalType: 'uint256',
"name": "value", name: 'value',
"type": "uint256" type: 'uint256',
}, },
{ {
"internalType": "bytes32", internalType: 'bytes32',
"name": "salt", name: 'salt',
"type": "bytes32" type: 'bytes32',
}, },
{ {
"internalType": "bytes", internalType: 'bytes',
"name": "code", name: 'code',
"type": "bytes" type: 'bytes',
} },
], ],
"name": "deploy", name: 'deploy',
"outputs": [], outputs: [],
"stateMutability": "nonpayable", stateMutability: 'nonpayable',
"type": "function" type: 'function',
}, },
{ {
"inputs": [ inputs: [
{ {
"internalType": "uint256", internalType: 'uint256',
"name": "value", name: 'value',
"type": "uint256" type: 'uint256',
}, },
{ {
"internalType": "bytes32", internalType: 'bytes32',
"name": "salt", name: 'salt',
"type": "bytes32" type: 'bytes32',
} },
], ],
"name": "deployERC1820Implementer", name: 'deployERC1820Implementer',
"outputs": [], outputs: [],
"stateMutability": "nonpayable", stateMutability: 'nonpayable',
"type": "function" type: 'function',
}, },
{ {
"inputs": [ inputs: [
{ {
"internalType": "address payable", internalType: 'address payable',
"name": "payoutAddress", name: 'payoutAddress',
"type": "address" type: 'address',
} },
], ],
"name": "killCreate2Deployer", name: 'killCreate2Deployer',
"outputs": [], outputs: [],
"stateMutability": "nonpayable", stateMutability: 'nonpayable',
"type": "function" type: 'function',
}, },
{ {
"inputs": [], inputs: [],
"name": "owner", name: 'owner',
"outputs": [ outputs: [
{ {
"internalType": "address", internalType: 'address',
"name": "", name: '',
"type": "address" type: 'address',
} },
], ],
"stateMutability": "view", stateMutability: 'view',
"type": "function" type: 'function',
}, },
{ {
"inputs": [], inputs: [],
"name": "pause", name: 'pause',
"outputs": [], outputs: [],
"stateMutability": "nonpayable", stateMutability: 'nonpayable',
"type": "function" type: 'function',
}, },
{ {
"inputs": [], inputs: [],
"name": "paused", name: 'paused',
"outputs": [ outputs: [
{ {
"internalType": "bool", internalType: 'bool',
"name": "", name: '',
"type": "bool" type: 'bool',
} },
], ],
"stateMutability": "view", stateMutability: 'view',
"type": "function" type: 'function',
}, },
{ {
"inputs": [], inputs: [],
"name": "renounceOwnership", name: 'renounceOwnership',
"outputs": [], outputs: [],
"stateMutability": "nonpayable", stateMutability: 'nonpayable',
"type": "function" type: 'function',
}, },
{ {
"inputs": [ inputs: [
{ {
"internalType": "address", internalType: 'address',
"name": "newOwner", name: 'newOwner',
"type": "address" type: 'address',
} },
], ],
"name": "transferOwnership", name: 'transferOwnership',
"outputs": [], outputs: [],
"stateMutability": "nonpayable", stateMutability: 'nonpayable',
"type": "function" type: 'function',
}, },
{ {
"inputs": [], inputs: [],
"name": "unpause", name: 'unpause',
"outputs": [], outputs: [],
"stateMutability": "nonpayable", stateMutability: 'nonpayable',
"type": "function" type: 'function',
}, },
{ {
"stateMutability": "payable", stateMutability: 'payable',
"type": "receive" type: 'receive',
} },
] ]

@ -17,7 +17,7 @@ More details are explained in the [documentation](https://remix-ide.readthedocs.
NOTE: When the remixd NPM module is installed, it also installs [Slither](https://github.com/crytic/slither), [solc-select](https://github.com/crytic/solc-select#quickstart) and sets [solc](https://docs.soliditylang.org/en/latest/installing-solidity.html) to latest version i.e. 0.8.15 currently. NOTE: When the remixd NPM module is installed, it also installs [Slither](https://github.com/crytic/slither), [solc-select](https://github.com/crytic/solc-select#quickstart) and sets [solc](https://docs.soliditylang.org/en/latest/installing-solidity.html) to latest version i.e. 0.8.15 currently.
ALSO NOTE: Python3.6+ (pip3) needs to already be installed on the System. In case of any discrepany, Slither can also installed along with other dependencies using command: ALSO NOTE: Python3.6+ (pip3) needs to already be installed on the System. In case of any discrepancy, Slither can also be installed along with other dependencies using the command:
``` ```
> remixd -i slither > remixd -i slither
``` ```

@ -113,8 +113,7 @@
"watch": "watchify apps/remix-ide/src/index.js -dv -p browserify-reload -o apps/remix-ide/build/app.js --exclude solc", "watch": "watchify apps/remix-ide/src/index.js -dv -p browserify-reload -o apps/remix-ide/build/app.js --exclude solc",
"reinstall": "rm ./node-modules/ -rf && rm yarn.lock && rm ./build/ -rf && yarn install & yarn run build", "reinstall": "rm ./node-modules/ -rf && rm yarn.lock && rm ./build/ -rf && yarn install & yarn run build",
"ganache-cli": "npx ganache-cli", "ganache-cli": "npx ganache-cli",
"build-contracts": "find ./node_modules/@openzeppelin/contracts | grep -i '.sol' > libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt && find ./node_modules/@uniswap/v3-core/contracts | grep -i '.sol' >> libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt", "build-contracts": "find ./node_modules/@openzeppelin/contracts | grep -i '.sol' > libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt && find ./node_modules/@uniswap/v3-core/contracts | grep -i '.sol' >> libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt"
"prepare": "husky install"
}, },
"dependencies": { "dependencies": {
"@babel/plugin-proposal-class-properties": "^7.16.0", "@babel/plugin-proposal-class-properties": "^7.16.0",
@ -140,7 +139,7 @@
"@remixproject/plugin-webview": "0.3.33", "@remixproject/plugin-webview": "0.3.33",
"@remixproject/plugin-ws": "0.3.33", "@remixproject/plugin-ws": "0.3.33",
"@types/nightwatch": "^2.3.1", "@types/nightwatch": "^2.3.1",
"@web3modal/ethereum": "^2.6.2", "@web3modal/ethereum": "^2.7.1",
"@web3modal/react": "^2.6.2", "@web3modal/react": "^2.6.2",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^2.6.2", "async": "^2.6.2",
@ -150,6 +149,7 @@
"brace": "^0.8.0", "brace": "^0.8.0",
"change-case": "^4.1.1", "change-case": "^4.1.1",
"chokidar": "^2.1.8", "chokidar": "^2.1.8",
"circom_wasm": "^0.0.2",
"color-support": "^1.1.3", "color-support": "^1.1.3",
"commander": "^9.4.1", "commander": "^9.4.1",
"core-js": "^3.6.5", "core-js": "^3.6.5",
@ -179,6 +179,7 @@
"latest-version": "^5.1.0", "latest-version": "^5.1.0",
"merge": "^2.1.1", "merge": "^2.1.1",
"npm-install-version": "^6.0.2", "npm-install-version": "^6.0.2",
"openai": "^3.3.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"prettier": "^2.8.4", "prettier": "^2.8.4",
"prettier-plugin-solidity": "^1.0.0-beta.24", "prettier-plugin-solidity": "^1.0.0-beta.24",
@ -208,8 +209,8 @@
"tree-kill": "^1.2.2", "tree-kill": "^1.2.2",
"ts-loader": "^9.2.6", "ts-loader": "^9.2.6",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"viem": "^1.2.12", "viem": "^1.6.0",
"wagmi": "^1.3.8", "wagmi": "^1.3.10",
"web3": "^4.1.0", "web3": "^4.1.0",
"winston": "^3.3.3", "winston": "^3.3.3",
"ws": "^7.3.0" "ws": "^7.3.0"
@ -229,7 +230,7 @@
"@babel/preset-typescript": "^7.18.6", "@babel/preset-typescript": "^7.18.6",
"@babel/register": "^7.4.4", "@babel/register": "^7.4.4",
"@fortawesome/fontawesome-free": "^5.8.1", "@fortawesome/fontawesome-free": "^5.8.1",
"@monaco-editor/react": "4.4.5", "@monaco-editor/react": "4.5.1",
"@nrwl/cli": "^15.7.1", "@nrwl/cli": "^15.7.1",
"@nrwl/eslint-plugin-nx": "^15.7.1", "@nrwl/eslint-plugin-nx": "^15.7.1",
"@nrwl/js": "15.7.1", "@nrwl/js": "15.7.1",
@ -328,7 +329,7 @@
"minixhr": "^4.0.0", "minixhr": "^4.0.0",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"mocha": "^8.0.1", "mocha": "^8.0.1",
"monaco-editor": "^0.30.1", "monaco-editor": "0.41.0",
"nanohtml": "^1.6.3", "nanohtml": "^1.6.3",
"nightwatch": "^2.3", "nightwatch": "^2.3",
"nodemon": "^2.0.4", "nodemon": "^2.0.4",
@ -368,10 +369,5 @@
}, },
"resolutions": { "resolutions": {
"@types/react": "^17.0.24" "@types/react": "^17.0.24"
},
"husky": {
"hooks": {
"pre-commit": "pretty-quick --staged --pattern \"**/*.{js,jsx,ts,tsx}\""
}
} }
} }

@ -0,0 +1,3 @@
{
"**/*.{tsx,ts,js}": ["prettier --write","eslint --fix"]
}

@ -3643,20 +3643,19 @@
semver "^7.3.8" semver "^7.3.8"
superstruct "^1.0.3" superstruct "^1.0.3"
"@monaco-editor/loader@^1.3.2": "@monaco-editor/loader@^1.3.3":
version "1.3.2" version "1.3.3"
resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.3.2.tgz#04effbb87052d19cd7d3c9d81c0635490f9bb6d8" resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.3.3.tgz#7f1742bd3cc21c0362a46a4056317f6e5215cfca"
integrity sha512-BTDbpHl3e47r3AAtpfVFTlAi7WXv4UQ/xZmz8atKl4q7epQV5e7+JbigFDViWF71VBi4IIBdcWP57Hj+OWuc9g== integrity sha512-6KKF4CTzcJiS8BJwtxtfyYt9shBiEv32ateQ9T4UVogwn4HM/uPo9iJd2Dmbkpz8CM6Y0PDUpjnZzCwC+eYo2Q==
dependencies: dependencies:
state-local "^1.0.6" state-local "^1.0.6"
"@monaco-editor/react@4.4.5": "@monaco-editor/react@4.5.1":
version "4.4.5" version "4.5.1"
resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.4.5.tgz#beabe491efeb2457441a00d1c7651c653697f65b" resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.5.1.tgz#fbc76c692aee9a33b9ab24ae0c5f219b8f002fdb"
integrity sha512-IImtzU7sRc66OOaQVCG+5PFHkSWnnhrUWGBuH6zNmH2h0YgmAhcjHZQc/6MY9JWEbUtVF1WPBMJ9u1XuFbRrVA== integrity sha512-NNDFdP+2HojtNhCkRfE6/D6ro6pBNihaOzMbGK84lNWzRu+CfBjwzGt4jmnqimLuqp5yE5viHS2vi+QOAnD5FQ==
dependencies: dependencies:
"@monaco-editor/loader" "^1.3.2" "@monaco-editor/loader" "^1.3.3"
prop-types "^15.7.2"
"@motionone/animation@^10.15.1": "@motionone/animation@^10.15.1":
version "10.15.1" version "10.15.1"
@ -3764,6 +3763,13 @@
dependencies: dependencies:
"@noble/hashes" "1.3.0" "@noble/hashes" "1.3.0"
"@noble/curves@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d"
integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==
dependencies:
"@noble/hashes" "1.3.1"
"@noble/ed25519@^1.7.0": "@noble/ed25519@^1.7.0":
version "1.7.3" version "1.7.3"
resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123" resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123"
@ -3779,6 +3785,11 @@
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1"
integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg== integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==
"@noble/hashes@1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
"@noble/secp256k1@1.7.1", "@noble/secp256k1@^1.6.3", "@noble/secp256k1@~1.7.0": "@noble/secp256k1@1.7.1", "@noble/secp256k1@^1.6.3", "@noble/secp256k1@~1.7.0":
version "1.7.1" version "1.7.1"
resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c"
@ -5869,7 +5880,7 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/ws@^8.5.3": "@types/ws@^8.5.4":
version "8.5.5" version "8.5.5"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb"
integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==
@ -5997,56 +6008,61 @@
resolved "https://registry.yarnpkg.com/@wagmi/chains/-/chains-1.2.0.tgz#d59eaa70ec51a5fdcd113975926992acfb17ab12" resolved "https://registry.yarnpkg.com/@wagmi/chains/-/chains-1.2.0.tgz#d59eaa70ec51a5fdcd113975926992acfb17ab12"
integrity sha512-dmDRipsE54JfyudOBkuhEexqQWcrZqxn/qiujG8SBzMh/az/AH5xlJSA+j1CPWTx9+QofSMF3B7A4gb6XRmSaQ== integrity sha512-dmDRipsE54JfyudOBkuhEexqQWcrZqxn/qiujG8SBzMh/az/AH5xlJSA+j1CPWTx9+QofSMF3B7A4gb6XRmSaQ==
"@wagmi/chains@1.5.0": "@wagmi/chains@1.6.0":
version "1.5.0" version "1.6.0"
resolved "https://registry.yarnpkg.com/@wagmi/chains/-/chains-1.5.0.tgz#0b23a1505704b4b07a46f41e1ec65a486aceb16b" resolved "https://registry.yarnpkg.com/@wagmi/chains/-/chains-1.6.0.tgz#eb992ad28dbaaab729b5bcab3e5b461e8a035656"
integrity sha512-JO5iqh7Km4GW/6XKKDYMq3YQ9wlOSGzzaTUQhALQ58KANxEZ70tZWhfTZAPD3fdgv4wheai7kyHDNgTW6X7fnw== integrity sha512-5FRlVxse5P4ZaHG3GTvxwVANSmYJas1eQrTBHhjxVtqXoorm0aLmCHbhmN8Xo1yu09PaWKlleEvfE98yH4AgIw==
"@wagmi/connectors@2.6.6": "@wagmi/chains@1.7.0":
version "2.6.6" version "1.7.0"
resolved "https://registry.yarnpkg.com/@wagmi/connectors/-/connectors-2.6.6.tgz#98f0f90831ed8d76295f44b1b85439ce0118bf70" resolved "https://registry.yarnpkg.com/@wagmi/chains/-/chains-1.7.0.tgz#8f6ad81cf867e1788417f7c978ca92bc083ecaf6"
integrity sha512-/o1c/TCivQs8DOAUOcQvY2UIt3p2mWOAHi39D0LC74+ncpXzLC5/gyaWU38qnTxPM8s/PmTmaWDgz+VhICXrag== integrity sha512-TKVeHv0GqP5sV1yQ8BDGYToAFezPnCexbbBpeH14x7ywi5a1dDStPffpt9x+ytE6LJWkZ6pAMs/HNWXBQ5Nqmw==
"@wagmi/connectors@2.7.0":
version "2.7.0"
resolved "https://registry.yarnpkg.com/@wagmi/connectors/-/connectors-2.7.0.tgz#547972502cbe6719217043fe5b610ac48534dc93"
integrity sha512-1KOL0HTJl5kzSC/YdKwFwiokr6poUQn1V/tcT0TpG3iH2x0lSM7FTkvCjVVY/6lKzTXrLlo9y2aE7AsOPnkvqg==
dependencies: dependencies:
"@coinbase/wallet-sdk" "^3.6.6" "@coinbase/wallet-sdk" "^3.6.6"
"@ledgerhq/connect-kit-loader" "^1.1.0" "@ledgerhq/connect-kit-loader" "^1.1.0"
"@safe-global/safe-apps-provider" "^0.17.1" "@safe-global/safe-apps-provider" "^0.17.1"
"@safe-global/safe-apps-sdk" "^8.0.0" "@safe-global/safe-apps-sdk" "^8.0.0"
"@walletconnect/ethereum-provider" "2.9.0" "@walletconnect/ethereum-provider" "2.9.2"
"@walletconnect/legacy-provider" "^2.0.0" "@walletconnect/legacy-provider" "^2.0.0"
"@walletconnect/modal" "2.5.9" "@walletconnect/modal" "2.6.1"
"@walletconnect/utils" "2.9.0" "@walletconnect/utils" "2.9.2"
abitype "0.8.7" abitype "0.8.7"
eventemitter3 "^4.0.7" eventemitter3 "^4.0.7"
"@wagmi/core@1.3.7": "@wagmi/core@1.3.9":
version "1.3.7" version "1.3.9"
resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-1.3.7.tgz#7bc00d172d206ffa171df0d5a813c3559d8824e3" resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-1.3.9.tgz#16bac164fe74203fde68abe7991b947d3a26e6ab"
integrity sha512-ens31RwICdrbRanNYwlJs0DAw/LOqUPQm6qXsmEciOENT4w+7pC959LXU9xfaOADWVMekeLDmRqAGCszTNIXAg== integrity sha512-SrnABCrsDvhiMCLLLyzyHnZbEumsFT/XWlJJQZeyEDcixL95R7XQwOaaoRI4MpNilCtMtu3jzN57tA5Z2iA+kw==
dependencies: dependencies:
"@wagmi/chains" "1.5.0" "@wagmi/chains" "1.7.0"
"@wagmi/connectors" "2.6.6" "@wagmi/connectors" "2.7.0"
abitype "0.8.7" abitype "0.8.7"
eventemitter3 "^4.0.7" eventemitter3 "^4.0.7"
zustand "^4.3.1" zustand "^4.3.1"
"@walletconnect/core@2.9.0": "@walletconnect/core@2.9.2":
version "2.9.0" version "2.9.2"
resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.9.0.tgz#7837a5d015a22b48d35b987bcde2aa9ccdf300d8" resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.9.2.tgz#c46734ca63771b28fd77606fd521930b7ecfc5e1"
integrity sha512-MZYJghS9YCvGe32UOgDj0mCasaOoGHQaYXWeQblXE/xb8HuaM6kAWhjIQN9P+MNp5QP134BHP5olQostcCotXQ== integrity sha512-VARMPAx8sIgodeyngDHbealP3B621PQqjqKsByFUTOep8ZI1/R/20zU+cmq6j9RCrL+kLKZcrZqeVzs8Z7OlqQ==
dependencies: dependencies:
"@walletconnect/heartbeat" "1.2.1" "@walletconnect/heartbeat" "1.2.1"
"@walletconnect/jsonrpc-provider" "1.0.13" "@walletconnect/jsonrpc-provider" "1.0.13"
"@walletconnect/jsonrpc-types" "1.0.3" "@walletconnect/jsonrpc-types" "1.0.3"
"@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/jsonrpc-utils" "1.0.8"
"@walletconnect/jsonrpc-ws-connection" "1.0.12" "@walletconnect/jsonrpc-ws-connection" "1.0.13"
"@walletconnect/keyvaluestorage" "^1.0.2" "@walletconnect/keyvaluestorage" "^1.0.2"
"@walletconnect/logger" "^2.0.1" "@walletconnect/logger" "^2.0.1"
"@walletconnect/relay-api" "^1.0.9" "@walletconnect/relay-api" "^1.0.9"
"@walletconnect/relay-auth" "^1.0.4" "@walletconnect/relay-auth" "^1.0.4"
"@walletconnect/safe-json" "^1.0.2" "@walletconnect/safe-json" "^1.0.2"
"@walletconnect/time" "^1.0.2" "@walletconnect/time" "^1.0.2"
"@walletconnect/types" "2.9.0" "@walletconnect/types" "2.9.2"
"@walletconnect/utils" "2.9.0" "@walletconnect/utils" "2.9.2"
events "^3.3.0" events "^3.3.0"
lodash.isequal "4.5.0" lodash.isequal "4.5.0"
uint8arrays "^3.1.0" uint8arrays "^3.1.0"
@ -6079,19 +6095,19 @@
dependencies: dependencies:
tslib "1.14.1" tslib "1.14.1"
"@walletconnect/ethereum-provider@2.9.0": "@walletconnect/ethereum-provider@2.9.2":
version "2.9.0" version "2.9.2"
resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.9.0.tgz#aa6e9e441678c824af8f744c50dafd604f19d69e" resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.9.2.tgz#fb3a6fca279bb4e98e75baa2fb9730545d41bb99"
integrity sha512-rSXkC0SXMigJRdIi/M2RMuEuATY1AwtlTWQBnqyxoht7xbO2bQNPCXn0XL4s/GRNrSUtoKSY4aPMHXV4W4yLBA== integrity sha512-eO1dkhZffV1g7vpG19XUJTw09M/bwGUwwhy1mJ3AOPbOSbMPvwiCuRz2Kbtm1g9B0Jv15Dl+TvJ9vTgYF8zoZg==
dependencies: dependencies:
"@walletconnect/jsonrpc-http-connection" "^1.0.7" "@walletconnect/jsonrpc-http-connection" "^1.0.7"
"@walletconnect/jsonrpc-provider" "^1.0.13" "@walletconnect/jsonrpc-provider" "^1.0.13"
"@walletconnect/jsonrpc-types" "^1.0.3" "@walletconnect/jsonrpc-types" "^1.0.3"
"@walletconnect/jsonrpc-utils" "^1.0.8" "@walletconnect/jsonrpc-utils" "^1.0.8"
"@walletconnect/sign-client" "2.9.0" "@walletconnect/sign-client" "2.9.2"
"@walletconnect/types" "2.9.0" "@walletconnect/types" "2.9.2"
"@walletconnect/universal-provider" "2.9.0" "@walletconnect/universal-provider" "2.9.2"
"@walletconnect/utils" "2.9.0" "@walletconnect/utils" "2.9.2"
events "^3.3.0" events "^3.3.0"
"@walletconnect/events@^1.0.1": "@walletconnect/events@^1.0.1":
@ -6192,10 +6208,10 @@
"@walletconnect/jsonrpc-types" "^1.0.2" "@walletconnect/jsonrpc-types" "^1.0.2"
tslib "1.14.1" tslib "1.14.1"
"@walletconnect/jsonrpc-ws-connection@1.0.12": "@walletconnect/jsonrpc-ws-connection@1.0.13":
version "1.0.12" version "1.0.13"
resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.12.tgz#2192314884fabdda6d0a9d22e157e5b352025ed8" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.13.tgz#23b0cdd899801bfbb44a6556936ec2b93ef2adf4"
integrity sha512-HAcadga3Qjt1Cqy+qXEW6zjaCs8uJGdGQrqltzl3OjiK4epGZRdvSzTe63P+t/3z+D2wG+ffEPn0GVcDozmN1w== integrity sha512-mfOM7uFH4lGtQxG+XklYuFBj6dwVvseTt5/ahOkkmpcAEgz2umuzu7fTR+h5EmjQBdrmYyEBOWADbeaFNxdySg==
dependencies: dependencies:
"@walletconnect/jsonrpc-utils" "^1.0.6" "@walletconnect/jsonrpc-utils" "^1.0.6"
"@walletconnect/safe-json" "^1.0.2" "@walletconnect/safe-json" "^1.0.2"
@ -6279,31 +6295,30 @@
pino "7.11.0" pino "7.11.0"
tslib "1.14.1" tslib "1.14.1"
"@walletconnect/modal-core@2.5.9": "@walletconnect/modal-core@2.6.1":
version "2.5.9" version "2.6.1"
resolved "https://registry.yarnpkg.com/@walletconnect/modal-core/-/modal-core-2.5.9.tgz#45e0c25320d42855aaac39e6ba256a84f972b871" resolved "https://registry.yarnpkg.com/@walletconnect/modal-core/-/modal-core-2.6.1.tgz#bc76055d0b644a2d4b98024324825c108a700905"
integrity sha512-isIebwF9hOknGouhS/Ob4YJ9Sa/tqNYG2v6Ua9EkCqIoLimepkG5eC53tslUWW29SLSfQ9qqBNG2+iE7yQXqgw== integrity sha512-f2hYlJ5pwzGvjyaZ6BoGR5uiMgXzWXt6w6ktt1N8lmY6PiYp8whZgqx2hTxVWwVlsGnaIfh6UHp1hGnANx0eTQ==
dependencies: dependencies:
buffer "6.0.3" valtio "1.11.0"
valtio "1.10.6"
"@walletconnect/modal-ui@2.5.9": "@walletconnect/modal-ui@2.6.1":
version "2.5.9" version "2.6.1"
resolved "https://registry.yarnpkg.com/@walletconnect/modal-ui/-/modal-ui-2.5.9.tgz#4d07f1697147ec9f75d85d93f564cadae05a5e59" resolved "https://registry.yarnpkg.com/@walletconnect/modal-ui/-/modal-ui-2.6.1.tgz#200c54c8dfe3c71321abb2724e18bb357dfd6371"
integrity sha512-nfBaAT9Ls7RZTBBgAq+Nt/3AoUcinIJ9bcq5UHXTV3lOPu/qCKmUC/0HY3GvUK8ykabUAsjr0OAGmcqkB91qug== integrity sha512-RFUOwDAMijSK8B7W3+KoLKaa1l+KEUG0LCrtHqaB0H0cLnhEGdLR+kdTdygw+W8+yYZbkM5tXBm7MlFbcuyitA==
dependencies: dependencies:
"@walletconnect/modal-core" "2.5.9" "@walletconnect/modal-core" "2.6.1"
lit "2.7.5" lit "2.7.6"
motion "10.16.2" motion "10.16.2"
qrcode "1.5.3" qrcode "1.5.3"
"@walletconnect/modal@2.5.9": "@walletconnect/modal@2.6.1":
version "2.5.9" version "2.6.1"
resolved "https://registry.yarnpkg.com/@walletconnect/modal/-/modal-2.5.9.tgz#28840f2a46bcd0a47c5fda60d18a5f1607a92a72" resolved "https://registry.yarnpkg.com/@walletconnect/modal/-/modal-2.6.1.tgz#066fdbfcff83b58c8a9da66ab4af0eb93e3626de"
integrity sha512-Zs2RvPwbBNRdBhb50FuJCxi3FJltt1KSpI7odjU/x9GTpTOcSOkmR66PBCy2JvNA0+ztnS1Xs0LVEr3lu7/Jzw== integrity sha512-G84tSzdPKAFk1zimgV7JzIUFT5olZUVtI3GcOk77OeLYjlMfnDT23RVRHm5EyCrjkptnvpD0wQScXePOFd2Xcw==
dependencies: dependencies:
"@walletconnect/modal-core" "2.5.9" "@walletconnect/modal-core" "2.6.1"
"@walletconnect/modal-ui" "2.5.9" "@walletconnect/modal-ui" "2.6.1"
"@walletconnect/randombytes@^1.0.3": "@walletconnect/randombytes@^1.0.3":
version "1.0.3" version "1.0.3"
@ -6349,19 +6364,19 @@
dependencies: dependencies:
tslib "1.14.1" tslib "1.14.1"
"@walletconnect/sign-client@2.9.0": "@walletconnect/sign-client@2.9.2":
version "2.9.0" version "2.9.2"
resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.9.0.tgz#fd3b0acb68bc8d56350f01ed70f8c6326e6e89fa" resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.9.2.tgz#ff4c81c082c2078878367d07f24bcb20b1f7ab9e"
integrity sha512-mEKc4LlLMebCe45qzqh+MX4ilQK4kOEBzLY6YJpG8EhyT45eX4JMNA7qQoYa9MRMaaVb/7USJcc4e3ZrjZvQmA== integrity sha512-anRwnXKlR08lYllFMEarS01hp1gr6Q9XUgvacr749hoaC/AwGVlxYFdM8+MyYr3ozlA+2i599kjbK/mAebqdXg==
dependencies: dependencies:
"@walletconnect/core" "2.9.0" "@walletconnect/core" "2.9.2"
"@walletconnect/events" "^1.0.1" "@walletconnect/events" "^1.0.1"
"@walletconnect/heartbeat" "1.2.1" "@walletconnect/heartbeat" "1.2.1"
"@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/jsonrpc-utils" "1.0.8"
"@walletconnect/logger" "^2.0.1" "@walletconnect/logger" "^2.0.1"
"@walletconnect/time" "^1.0.2" "@walletconnect/time" "^1.0.2"
"@walletconnect/types" "2.9.0" "@walletconnect/types" "2.9.2"
"@walletconnect/utils" "2.9.0" "@walletconnect/utils" "2.9.2"
events "^3.3.0" events "^3.3.0"
"@walletconnect/time@^1.0.2": "@walletconnect/time@^1.0.2":
@ -6371,10 +6386,10 @@
dependencies: dependencies:
tslib "1.14.1" tslib "1.14.1"
"@walletconnect/types@2.9.0": "@walletconnect/types@2.9.2":
version "2.9.0" version "2.9.2"
resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.9.0.tgz#6e5dfdc7212c1ec4ab49a1ec409c743e16093f72" resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.9.2.tgz#d5fd5a61dc0f41cbdca59d1885b85207ac7bf8c5"
integrity sha512-ORopsMfSRvUYqtjKKd6scfg8o4/aGebipLxx92AuuUgMTERSU6cGmIrK6rdLu7W6FBJkmngPLEGc9mRqAb9Lug== integrity sha512-7Rdn30amnJEEal4hk83cdwHUuxI1SWQ+K7fFFHBMqkuHLGi3tpMY6kpyfDxnUScYEZXqgRps4Jo5qQgnRqVM7A==
dependencies: dependencies:
"@walletconnect/events" "^1.0.1" "@walletconnect/events" "^1.0.1"
"@walletconnect/heartbeat" "1.2.1" "@walletconnect/heartbeat" "1.2.1"
@ -6383,25 +6398,25 @@
"@walletconnect/logger" "^2.0.1" "@walletconnect/logger" "^2.0.1"
events "^3.3.0" events "^3.3.0"
"@walletconnect/universal-provider@2.9.0": "@walletconnect/universal-provider@2.9.2":
version "2.9.0" version "2.9.2"
resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.9.0.tgz#a6b4a1f099262536e17b5c25bf7b3c89db9945a8" resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.9.2.tgz#40e54e98bc48b1f2f5f77eb5b7f05462093a8506"
integrity sha512-k3nkSBkF69sJJVoe17IVoPtnhp/sgaa2t+x7BvA/BKeMxE0DGdtRJdEXotTc8DBmI7o2tkq6l8+HyFBGjQ/CjQ== integrity sha512-JmaolkO8D31UdRaQCHwlr8uIFUI5BYhBzqYFt54Mc6gbIa1tijGOmdyr6YhhFO70LPmS6gHIjljwOuEllmlrxw==
dependencies: dependencies:
"@walletconnect/jsonrpc-http-connection" "^1.0.7" "@walletconnect/jsonrpc-http-connection" "^1.0.7"
"@walletconnect/jsonrpc-provider" "1.0.13" "@walletconnect/jsonrpc-provider" "1.0.13"
"@walletconnect/jsonrpc-types" "^1.0.2" "@walletconnect/jsonrpc-types" "^1.0.2"
"@walletconnect/jsonrpc-utils" "^1.0.7" "@walletconnect/jsonrpc-utils" "^1.0.7"
"@walletconnect/logger" "^2.0.1" "@walletconnect/logger" "^2.0.1"
"@walletconnect/sign-client" "2.9.0" "@walletconnect/sign-client" "2.9.2"
"@walletconnect/types" "2.9.0" "@walletconnect/types" "2.9.2"
"@walletconnect/utils" "2.9.0" "@walletconnect/utils" "2.9.2"
events "^3.3.0" events "^3.3.0"
"@walletconnect/utils@2.9.0": "@walletconnect/utils@2.9.2":
version "2.9.0" version "2.9.2"
resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.9.0.tgz#c73925edb9fefe79021bcf028e957028f986b728" resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.9.2.tgz#035bdb859ee81a4bcc6420f56114cc5ec3e30afb"
integrity sha512-7Tu3m6dZL84KofrNBcblsgpSqU2vdo9ImLD7zWimLXERVGNQ8smXG+gmhQYblebIBhsPzjy9N38YMC3nPlfQNw== integrity sha512-D44hwXET/8JhhIjqljY6qxSu7xXnlPrf63UN/Qfl98vDjWlYVcDl2+JIQRxD9GPastw0S8XZXdRq59XDXLuZBg==
dependencies: dependencies:
"@stablelib/chacha20poly1305" "1.0.1" "@stablelib/chacha20poly1305" "1.0.1"
"@stablelib/hkdf" "1.0.1" "@stablelib/hkdf" "1.0.1"
@ -6411,7 +6426,7 @@
"@walletconnect/relay-api" "^1.0.9" "@walletconnect/relay-api" "^1.0.9"
"@walletconnect/safe-json" "^1.0.2" "@walletconnect/safe-json" "^1.0.2"
"@walletconnect/time" "^1.0.2" "@walletconnect/time" "^1.0.2"
"@walletconnect/types" "2.9.0" "@walletconnect/types" "2.9.2"
"@walletconnect/window-getters" "^1.0.1" "@walletconnect/window-getters" "^1.0.1"
"@walletconnect/window-metadata" "^1.0.1" "@walletconnect/window-metadata" "^1.0.1"
detect-browser "5.3.0" detect-browser "5.3.0"
@ -6441,10 +6456,10 @@
buffer "6.0.3" buffer "6.0.3"
valtio "1.10.6" valtio "1.10.6"
"@web3modal/ethereum@^2.6.2": "@web3modal/ethereum@^2.7.1":
version "2.6.2" version "2.7.1"
resolved "https://registry.yarnpkg.com/@web3modal/ethereum/-/ethereum-2.6.2.tgz#e6522ddf00444cb3e6e54d390a74864c329cee5e" resolved "https://registry.yarnpkg.com/@web3modal/ethereum/-/ethereum-2.7.1.tgz#464dbc1d00d075c16961b77e9a353b1966538653"
integrity sha512-8QCzJj0+x6y/7V++DQnXdPjdmMvq+zm/Fl8CEKhNlni9p4H406q7ramjdJEu1Bk4xtCklYh/aU3ZGR5wUIDysA== integrity sha512-1x3qhYh9qgtvw1MDQD4VeDf2ZOsVANKRPtUty4lF+N4L8xnAIwvNKUAMA4j6T5xSsjqUfq5Tdy5mYsNxLmsWMA==
"@web3modal/react@^2.6.2": "@web3modal/react@^2.6.2":
version "2.6.2" version "2.6.2"
@ -6687,6 +6702,11 @@ abitype@0.8.7:
resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.8.7.tgz#e4b3f051febd08111f486c0cc6a98fa72d033622" resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.8.7.tgz#e4b3f051febd08111f486c0cc6a98fa72d033622"
integrity sha512-wQ7hV8Yg/yKmGyFpqrNZufCxbszDe5es4AZGYPBitocfSqXtjrTG9JMWFcc4N30ukl2ve48aBTwt7NJxVQdU3w== integrity sha512-wQ7hV8Yg/yKmGyFpqrNZufCxbszDe5es4AZGYPBitocfSqXtjrTG9JMWFcc4N30ukl2ve48aBTwt7NJxVQdU3w==
abitype@0.9.3:
version "0.9.3"
resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.3.tgz#294d25288ee683d72baf4e1fed757034e3c8c277"
integrity sha512-dz4qCQLurx97FQhnb/EIYTk/ldQ+oafEDUqC0VVIeQS1Q48/YWt/9YNfMmp9SLFqN41ktxny3c8aYxHjmFIB/w==
abort-controller@^3.0.0: abort-controller@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
@ -7570,6 +7590,13 @@ axios@^0.21.1:
dependencies: dependencies:
follow-redirects "^1.14.0" follow-redirects "^1.14.0"
axios@^0.26.0:
version "0.26.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
dependencies:
follow-redirects "^1.14.8"
axios@^1.4.0: axios@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f"
@ -9612,6 +9639,11 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
inherits "^2.0.1" inherits "^2.0.1"
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
circom_wasm@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/circom_wasm/-/circom_wasm-0.0.2.tgz#9d24866b8289a5778999270823a4cb06e64145b5"
integrity sha512-SCMP6cxHHL7MLedDrTl+nGYyE6+kE5GepbxtZm65GlR0wUMD9eNOD1shwScWaDnmBOZTrImmNeTYZA5DWCmIww==
circular-json@^0.3.0: circular-json@^0.3.0:
version "0.3.3" version "0.3.3"
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
@ -17487,6 +17519,15 @@ lit@2.7.5:
lit-element "^3.3.0" lit-element "^3.3.0"
lit-html "^2.7.0" lit-html "^2.7.0"
lit@2.7.6:
version "2.7.6"
resolved "https://registry.yarnpkg.com/lit/-/lit-2.7.6.tgz#810007b876ed43e0c70124de91831921598b1665"
integrity sha512-1amFHA7t4VaaDe+vdQejSVBklwtH9svGoG6/dZi9JhxtJBBlqY5D1RV7iLUYY0trCqQc4NfhYYZilZiVHt7Hxg==
dependencies:
"@lit/reactive-element" "^1.6.0"
lit-element "^3.3.0"
lit-html "^2.7.0"
load-json-file@^1.0.0: load-json-file@^1.0.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@ -19196,10 +19237,10 @@ mold-source-map@~0.4.0:
convert-source-map "^1.1.0" convert-source-map "^1.1.0"
through "~2.2.7" through "~2.2.7"
monaco-editor@^0.30.1: monaco-editor@0.41.0:
version "0.30.1" version "0.41.0"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.30.1.tgz#47f8d18a0aa2264fc5654581741ab8d7bec01689" resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.41.0.tgz#2ba31e5af7e3ae93ac5d7467ec2772ef9b3d967f"
integrity sha512-B/y4+b2O5G2gjuxIFtCE2EkM17R2NM7/3F8x0qcPsqy4V83bitJTIO4TIeZpYlzu/xy6INiY/+84BEm6+7Cmzg== integrity sha512-1o4olnZJsiLmv5pwLEAmzHTE/5geLKQ07BrGxlF4Ri/AXAc2yyDGZwHjiTqD8D/ROKUZmwMA28A+yEowLNOEcA==
motion@10.16.2: motion@10.16.2:
version "10.16.2" version "10.16.2"
@ -20567,6 +20608,14 @@ open@^8.0.9, open@^8.4.0:
is-docker "^2.1.1" is-docker "^2.1.1"
is-wsl "^2.2.0" is-wsl "^2.2.0"
openai@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/openai/-/openai-3.3.0.tgz#a6408016ad0945738e1febf43f2fccca83a3f532"
integrity sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ==
dependencies:
axios "^0.26.0"
form-data "^4.0.0"
opener@^1.5.1, opener@^1.5.2: opener@^1.5.1, opener@^1.5.2:
version "1.5.2" version "1.5.2"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598"
@ -26632,6 +26681,14 @@ valtio@1.10.6:
proxy-compare "2.5.1" proxy-compare "2.5.1"
use-sync-external-store "1.2.0" use-sync-external-store "1.2.0"
valtio@1.11.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.11.0.tgz#c029dcd17a0f99d2fbec933721fe64cfd32a31ed"
integrity sha512-65Yd0yU5qs86b5lN1eu/nzcTgQ9/6YnD6iO+DDaDbQLn1Zv2w12Gwk43WkPlUBxk5wL/6cD5YMFf7kj6HZ1Kpg==
dependencies:
proxy-compare "2.5.1"
use-sync-external-store "1.2.0"
value-or-function@^3.0.0: value-or-function@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813" resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813"
@ -26677,7 +26734,7 @@ vfile@^5.0.0:
unist-util-stringify-position "^3.0.0" unist-util-stringify-position "^3.0.0"
vfile-message "^3.0.0" vfile-message "^3.0.0"
viem@^1.0.0, viem@^1.2.12: viem@^1.0.0:
version "1.2.12" version "1.2.12"
resolved "https://registry.yarnpkg.com/viem/-/viem-1.2.12.tgz#0342f52d05968bd1c2af5db0b9bc569926ae9151" resolved "https://registry.yarnpkg.com/viem/-/viem-1.2.12.tgz#0342f52d05968bd1c2af5db0b9bc569926ae9151"
integrity sha512-TMhvqT2VaCaJyBfuNDyL1h8xPFyPDHeX6Qab66TjWscnNcTwkW0gojO4Uh+A4RuPzFxIlWSW+b5SjS8SJHlHpg== integrity sha512-TMhvqT2VaCaJyBfuNDyL1h8xPFyPDHeX6Qab66TjWscnNcTwkW0gojO4Uh+A4RuPzFxIlWSW+b5SjS8SJHlHpg==
@ -26692,6 +26749,22 @@ viem@^1.0.0, viem@^1.2.12:
isomorphic-ws "5.0.0" isomorphic-ws "5.0.0"
ws "8.12.0" ws "8.12.0"
viem@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/viem/-/viem-1.6.0.tgz#8befa678c3ac79b9558dfd1708130b2ecb1994f4"
integrity sha512-ae9Twkd0q2Qlj4yYpWjb4DzYAhKY0ibEpRH8FJaTywZXNpTjFidSdBaT0CVn1BaH7O7cnX4/O47zvDUMGJD1AA==
dependencies:
"@adraffy/ens-normalize" "1.9.0"
"@noble/curves" "1.1.0"
"@noble/hashes" "1.3.0"
"@scure/bip32" "1.3.0"
"@scure/bip39" "1.2.0"
"@types/ws" "^8.5.4"
"@wagmi/chains" "1.6.0"
abitype "0.9.3"
isomorphic-ws "5.0.0"
ws "8.12.0"
vinyl-fs@^3.0.0: vinyl-fs@^3.0.0:
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7" resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7"
@ -26755,15 +26828,15 @@ w3c-blob@0.0.1:
resolved "https://registry.yarnpkg.com/w3c-blob/-/w3c-blob-0.0.1.tgz#b0cd352a1a50f515563420ffd5861f950f1d85b8" resolved "https://registry.yarnpkg.com/w3c-blob/-/w3c-blob-0.0.1.tgz#b0cd352a1a50f515563420ffd5861f950f1d85b8"
integrity sha1-sM01KhpQ9RVWNCD/1YYflQ8dhbg= integrity sha1-sM01KhpQ9RVWNCD/1YYflQ8dhbg=
wagmi@^1.3.8: wagmi@^1.3.10:
version "1.3.8" version "1.3.10"
resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-1.3.8.tgz#544554fdab35ee32d93f107eb75b9d1924e22880" resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-1.3.10.tgz#100aeaecf7a030e9e91118d366a734ec30c56551"
integrity sha512-RCfcE+Q+yhyfq7j5u7KQRz2KXUMAMexu0Y2kr8z81t4fmDlU5C+OEVQ6NFoUzAzEsJpznpQjZgsfpHKeFm17hQ== integrity sha512-MMGJcnxOmeUZWDmzUxgRGcB1cqxbJoSFSa+pNY4vBCWMz0n4ptpE5F8FKISLCx+BGoDwsaz2ldcMALcdJZ+29w==
dependencies: dependencies:
"@tanstack/query-sync-storage-persister" "^4.27.1" "@tanstack/query-sync-storage-persister" "^4.27.1"
"@tanstack/react-query" "^4.28.0" "@tanstack/react-query" "^4.28.0"
"@tanstack/react-query-persist-client" "^4.28.0" "@tanstack/react-query-persist-client" "^4.28.0"
"@wagmi/core" "1.3.7" "@wagmi/core" "1.3.9"
abitype "0.8.7" abitype "0.8.7"
use-sync-external-store "^1.2.0" use-sync-external-store "^1.2.0"

Loading…
Cancel
Save