parent
e42a392286
commit
e9c806d750
@ -0,0 +1,4 @@ |
|||||||
|
#!/usr/bin/env sh |
||||||
|
. "$(dirname -- "$0")/_/husky.sh" |
||||||
|
|
||||||
|
|
@ -0,0 +1,13 @@ |
|||||||
|
**/.yarn/* |
||||||
|
|
||||||
|
# Ignore node_modules |
||||||
|
./node_modules |
||||||
|
|
||||||
|
# Ignore e2e files |
||||||
|
./apps/remix-ide-e2e/* |
||||||
|
|
||||||
|
# Ignore build artefacts |
||||||
|
./dist |
||||||
|
|
||||||
|
# Ignore all json files |
||||||
|
**/*.json |
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"tabWidth": 2, |
||||||
|
"useTabs": false, |
||||||
|
"printWidth": 180, |
||||||
|
"semi": false, |
||||||
|
"singleQuote": true |
||||||
|
} |
@ -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": "hiddenPanel", |
||||||
|
"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,17 +1,17 @@ |
|||||||
import React, { useState, useEffect } from 'react'; |
import React, {useState, useEffect} from 'react' |
||||||
|
|
||||||
import { DebuggerUI } from '@remix-ui/debugger-ui' // eslint-disable-line
|
import {DebuggerUI} from '@remix-ui/debugger-ui' // eslint-disable-line
|
||||||
|
|
||||||
import { DebuggerClientApi } from './debugger' |
import {DebuggerClientApi} from './debugger' |
||||||
|
|
||||||
const remix = new DebuggerClientApi() |
const remix = new DebuggerClientApi() |
||||||
|
|
||||||
export const App = () => {
|
export const App = () => { |
||||||
return ( |
return ( |
||||||
<div className="debugger"> |
<div className="debugger"> |
||||||
<DebuggerUI debuggerAPI={remix} /> |
<DebuggerUI debuggerAPI={remix} /> |
||||||
</div> |
</div> |
||||||
); |
) |
||||||
}; |
} |
||||||
|
|
||||||
export default App; |
export default App |
||||||
|
@ -1,9 +1,6 @@ |
|||||||
import React from 'react'; |
import React from 'react' |
||||||
import ReactDOM from 'react-dom'; |
import ReactDOM from 'react-dom' |
||||||
|
|
||||||
import App from './app/app'; |
import App from './app/app' |
||||||
|
|
||||||
ReactDOM.render( |
ReactDOM.render(<App />, document.getElementById('root')) |
||||||
<App />, |
|
||||||
document.getElementById('root') |
|
||||||
); |
|
||||||
|
@ -1,31 +1,28 @@ |
|||||||
import React from "react"; |
import React from 'react' |
||||||
|
|
||||||
export const ErrorView: React.FC = () => { |
export const ErrorView: React.FC = () => { |
||||||
return ( |
return ( |
||||||
<div |
<div |
||||||
style={{ |
style={{ |
||||||
width: "100%", |
width: '100%', |
||||||
display: "flex", |
display: 'flex', |
||||||
flexDirection: "column", |
flexDirection: 'column', |
||||||
alignItems: "center", |
alignItems: 'center', |
||||||
}} |
}} |
||||||
> |
> |
||||||
<img |
<img |
||||||
style={{ paddingBottom: "2em" }} |
style={{ paddingBottom: '2em' }} |
||||||
width="250" |
width="250" |
||||||
src="https://res.cloudinary.com/key-solutions/image/upload/v1580400635/solid/error-png.png" |
src="https://res.cloudinary.com/key-solutions/image/upload/v1580400635/solid/error-png.png" |
||||||
alt="Error page" |
alt="Error page" |
||||||
/> |
/> |
||||||
<h5>Sorry, something unexpected happened. </h5> |
<h5>Sorry, something unexpected happened. </h5> |
||||||
<h5> |
<h5> |
||||||
Please raise an issue:{" "} |
Please raise an issue:{' '} |
||||||
<a |
<a style={{ color: 'red' }} href="https://github.com/Machinalabs/remix-ethdoc-plugin/issues"> |
||||||
style={{ color: "red" }} |
|
||||||
href="https://github.com/Machinalabs/remix-ethdoc-plugin/issues" |
|
||||||
> |
|
||||||
Here |
Here |
||||||
</a> |
</a> |
||||||
</h5> |
</h5> |
||||||
</div> |
</div> |
||||||
); |
) |
||||||
}; |
} |
||||||
|
@ -1,11 +1,11 @@ |
|||||||
import React from "react"; |
import React from 'react' |
||||||
import ReactDOM from "react-dom"; |
import ReactDOM from 'react-dom' |
||||||
import App from "./app/App"; |
import App from './app/App' |
||||||
// import { Routes } from "./routes";
|
// import { Routes } from "./routes";
|
||||||
|
|
||||||
ReactDOM.render( |
ReactDOM.render( |
||||||
<React.StrictMode> |
<React.StrictMode> |
||||||
<App /> |
<App /> |
||||||
</React.StrictMode>, |
</React.StrictMode>, |
||||||
document.getElementById("root") |
document.getElementById('root'), |
||||||
); |
) |
||||||
|
@ -1,24 +1,24 @@ |
|||||||
import React from "react" |
import React from 'react' |
||||||
import { PluginClient } from "@remixproject/plugin" |
import {PluginClient} from '@remixproject/plugin' |
||||||
|
|
||||||
import { Receipt, ThemeType } from "./types" |
import {Receipt, ThemeType} from './types' |
||||||
|
|
||||||
export const AppContext = React.createContext({ |
export const AppContext = React.createContext({ |
||||||
apiKey: "", |
apiKey: '', |
||||||
setAPIKey: (value: string) => { |
setAPIKey: (value: string) => { |
||||||
console.log("Set API Key from Context") |
console.log('Set API Key from Context') |
||||||
}, |
}, |
||||||
clientInstance: {} as PluginClient, |
clientInstance: {} as PluginClient, |
||||||
receipts: [] as Receipt[], |
receipts: [] as Receipt[], |
||||||
setReceipts: (receipts: Receipt[]) => { |
setReceipts: (receipts: Receipt[]) => { |
||||||
console.log("Calling Set Receipts") |
console.log('Calling Set Receipts') |
||||||
}, |
}, |
||||||
contracts: [] as string[], |
contracts: [] as string[], |
||||||
setContracts: (contracts: string[]) => { |
setContracts: (contracts: string[]) => { |
||||||
console.log("Calling Set Contract Names") |
console.log('Calling Set Contract Names') |
||||||
}, |
}, |
||||||
themeType: "dark" as ThemeType, |
themeType: 'dark' as ThemeType, |
||||||
setThemeType: (themeType: ThemeType) => { |
setThemeType: (themeType: ThemeType) => { |
||||||
console.log("Calling Set Theme Type") |
console.log('Calling Set Theme Type') |
||||||
}, |
} |
||||||
}) |
}) |
||||||
|
@ -1,40 +1,59 @@ |
|||||||
import { PluginClient } from '@remixproject/plugin'; |
import {PluginClient} from '@remixproject/plugin' |
||||||
import { verify, EtherScanReturn } from './utils/verify'; |
import {verify, EtherScanReturn} from './utils/verify' |
||||||
import { getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus } from './utils'; |
import {getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus} from './utils' |
||||||
|
|
||||||
export class RemixClient extends PluginClient { |
export class RemixClient extends PluginClient { |
||||||
|
loaded() { |
||||||
|
return this.onload() |
||||||
|
} |
||||||
|
|
||||||
loaded() { |
async verify( |
||||||
return this.onload() |
apiKey: string, |
||||||
} |
contractAddress: string, |
||||||
|
contractArguments: string, |
||||||
async verify (apiKey: string, contractAddress: string, contractArguments: string, contractName: string, compilationResultParam: any, chainRef?: number | string, isProxyContract?: boolean, expectedImplAddress?: string) { |
contractName: string, |
||||||
const result = await verify(apiKey, contractAddress, contractArguments, contractName, compilationResultParam, chainRef, isProxyContract, expectedImplAddress, this, |
compilationResultParam: any, |
||||||
(value: EtherScanReturn) => {}, (value: string) => {})
|
chainRef?: number | string, |
||||||
return result |
isProxyContract?: boolean, |
||||||
} |
expectedImplAddress?: string |
||||||
|
) { |
||||||
|
const result = await verify( |
||||||
|
apiKey, |
||||||
|
contractAddress, |
||||||
|
contractArguments, |
||||||
|
contractName, |
||||||
|
compilationResultParam, |
||||||
|
chainRef, |
||||||
|
isProxyContract, |
||||||
|
expectedImplAddress, |
||||||
|
this, |
||||||
|
(value: EtherScanReturn) => {}, |
||||||
|
(value: string) => {} |
||||||
|
) |
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
async receiptStatus(receiptGuid: string, apiKey: string, isProxyContract: boolean) { |
||||||
|
try { |
||||||
|
const {network, networkId} = await getNetworkName(this) |
||||||
|
if (network === 'vm') { |
||||||
|
throw new Error('Cannot check the receipt status in the selected network') |
||||||
|
} |
||||||
|
const etherscanApi = getEtherScanApi(networkId) |
||||||
|
let receiptStatus |
||||||
|
|
||||||
async receiptStatus (receiptGuid: string, apiKey: string, isProxyContract: boolean) { |
if (isProxyContract) receiptStatus = await getProxyContractReceiptStatus(receiptGuid, apiKey, etherscanApi) |
||||||
try { |
else receiptStatus = await getReceiptStatus(receiptGuid, apiKey, etherscanApi) |
||||||
const { network, networkId } = await getNetworkName(this) |
return { |
||||||
if (network === "vm") { |
message: receiptStatus.result, |
||||||
throw new Error("Cannot check the receipt status in the selected network") |
succeed: receiptStatus.status === '0' ? false : true |
||||||
} |
} |
||||||
const etherscanApi = getEtherScanApi(networkId) |
} catch (e: any) { |
||||||
let receiptStatus |
return { |
||||||
|
status: 'error', |
||||||
if (isProxyContract) receiptStatus = await getProxyContractReceiptStatus(receiptGuid, apiKey, etherscanApi) |
message: e.message, |
||||||
else receiptStatus = await getReceiptStatus(receiptGuid, apiKey, etherscanApi) |
succeed: false |
||||||
return { |
} |
||||||
message: receiptStatus.result, |
|
||||||
succeed: receiptStatus.status === '0' ? false : true |
|
||||||
} |
|
||||||
} catch (e: any){ |
|
||||||
return { |
|
||||||
status: 'error', |
|
||||||
message: e.message, |
|
||||||
succeed: false |
|
||||||
} |
|
||||||
}
|
|
||||||
} |
} |
||||||
|
} |
||||||
} |
} |
||||||
|
@ -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', |
||||||
|
} |
||||||
|
@ -1,7 +1,11 @@ |
|||||||
import { StrictMode } from 'react'; |
import {StrictMode} from 'react' |
||||||
import * as ReactDOM from 'react-dom'; |
import * as ReactDOM from 'react-dom' |
||||||
|
|
||||||
|
import App from './app/app' |
||||||
|
|
||||||
import App from './app/app'; |
ReactDOM.render( |
||||||
|
<StrictMode> |
||||||
ReactDOM.render(<StrictMode><App /></StrictMode>, document.getElementById('root')); |
<App /> |
||||||
|
</StrictMode>, |
||||||
|
document.getElementById('root') |
||||||
|
) |
||||||
|
@ -1,9 +1,13 @@ |
|||||||
import React from 'react' |
import React from 'react' |
||||||
interface loggerProps { |
interface loggerProps { |
||||||
log: any, |
log: any |
||||||
id: string |
id: string |
||||||
} |
} |
||||||
|
|
||||||
export const Logger: React.FC<loggerProps> = (props) => { |
export const Logger: React.FC<loggerProps> = (props) => { |
||||||
return (<div id={props.id} className="jumbotron overflow-auto text-break mb-1 p-2">{props.log}</div>) |
return ( |
||||||
|
<div id={props.id} className="jumbotron overflow-auto text-break mb-1 p-2"> |
||||||
|
{props.log} |
||||||
|
</div> |
||||||
|
) |
||||||
} |
} |
||||||
|
@ -0,0 +1,345 @@ |
|||||||
|
'use strict' |
||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
import init from '../helpers/init' |
||||||
|
|
||||||
|
let firstProxyAddress: string |
||||||
|
let lastProxyAddress: string |
||||||
|
let shortenedFirstAddress: string |
||||||
|
let shortenedLastAddress: string |
||||||
|
module.exports = { |
||||||
|
'@disabled': true, |
||||||
|
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||||
|
init(browser, done) |
||||||
|
}, |
||||||
|
|
||||||
|
'@sources': function () { |
||||||
|
return sources |
||||||
|
}, |
||||||
|
|
||||||
|
'Should set the compiler version to 8.19': function(browser: NightwatchBrowser) { |
||||||
|
browser.setSolidityCompilerVersion('soljson-v0.8.19+commit.7dd6d404.js') |
||||||
|
}, |
||||||
|
|
||||||
|
'Should show deploy proxy option for UUPS upgradeable contract #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.addFile('myTokenV1.sol', sources[0]['myTokenV1.sol']) |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.pause(2000) |
||||||
|
// because the compilatiom imports are slow and sometimes stop loading (not sure why, it's bug) we need to recompile and check to see if the files are really in de FS
|
||||||
|
.click('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.isVisible({ |
||||||
|
selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable@4.8.3/proxy/beacon/IBeaconUpgradeable.sol"]', |
||||||
|
timeout: 120000, |
||||||
|
suppressNotFoundErrors: true |
||||||
|
}) |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.click('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.isVisible({ |
||||||
|
selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable@4.8.3/proxy/beacon/IBeaconUpgradeable.sol"]', |
||||||
|
timeout: 120000, |
||||||
|
suppressNotFoundErrors: true |
||||||
|
}) |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.click('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.clickLaunchIcon('filePanel') |
||||||
|
.waitForElementVisible({ |
||||||
|
selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable@4.8.3/proxy/beacon/IBeaconUpgradeable.sol"]', |
||||||
|
timeout: 120000, |
||||||
|
}) |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.waitForElementPresent('select[id="compiledContracts"] option[value=MyToken]', 60000) |
||||||
|
.clickLaunchIcon('udapp') |
||||||
|
.click('select.udapp_contractNames') |
||||||
|
.click('select.udapp_contractNames option[value=MyToken]') |
||||||
|
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]') |
||||||
|
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]') |
||||||
|
}, |
||||||
|
|
||||||
|
'Should show upgrade proxy option for child contract inheriting UUPS parent contract #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.addFile('myTokenV2.sol', sources[1]['myTokenV2.sol']) |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.assert.visible('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.click('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000) |
||||||
|
.clickLaunchIcon('udapp') |
||||||
|
.click('select.udapp_contractNames') |
||||||
|
.click('select.udapp_contractNames option[value=MyTokenV2]') |
||||||
|
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]') |
||||||
|
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]') |
||||||
|
}, |
||||||
|
|
||||||
|
'Should deploy proxy without initialize parameters #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.openFile('myTokenV1.sol') |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.assert.visible('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.click('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.waitForElementPresent('select[id="compiledContracts"] option[value=MyToken]', 60000) |
||||||
|
.clickLaunchIcon('udapp') |
||||||
|
.click('select.udapp_contractNames') |
||||||
|
.click('select.udapp_contractNames option[value=MyToken]') |
||||||
|
.verify.visible('[data-id="contractGUIDeployWithProxyLabel"]') |
||||||
|
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]') |
||||||
|
.click('[data-id="contractGUIDeployWithProxyLabel"]') |
||||||
|
.createContract('') |
||||||
|
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)') |
||||||
|
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') |
||||||
|
.click('[data-id="udappNotify-modal-footer-ok-react"]') |
||||||
|
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Deploy Proxy (ERC1967)') |
||||||
|
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') |
||||||
|
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') |
||||||
|
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') |
||||||
|
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') |
||||||
|
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 < 5.0.0 as proxy...', 60000) |
||||||
|
}, |
||||||
|
|
||||||
|
'Should interact with deployed contract via ERC1967 (proxy) #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.getAddressAtPosition(1, (address) => { |
||||||
|
firstProxyAddress = address |
||||||
|
shortenedFirstAddress = address.slice(0, 5) + '...' + address.slice(address.length - 5, address.length) |
||||||
|
}) |
||||||
|
.clickInstance(1) |
||||||
|
.perform((done) => { |
||||||
|
browser.testConstantFunction(firstProxyAddress, 'name - call', null, '0:\nstring: MyToken').perform(() => { |
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
.perform((done) => { |
||||||
|
browser.testConstantFunction(firstProxyAddress, 'symbol - call', null, '0:\nstring: MTK').perform(() => { |
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'Should deploy proxy with initialize parameters #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.waitForElementPresent('[data-id="deployAndRunClearInstances"]') |
||||||
|
.click('[data-id="deployAndRunClearInstances"]') |
||||||
|
.addFile('initializeProxy.sol', sources[2]['initializeProxy.sol']) |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.assert.visible('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.click('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.waitForElementPresent('select[id="compiledContracts"] option[value=MyInitializedToken]', 60000) |
||||||
|
.clickLaunchIcon('udapp') |
||||||
|
.click('select.udapp_contractNames') |
||||||
|
.click('select.udapp_contractNames option[value=MyInitializedToken]') |
||||||
|
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]') |
||||||
|
.click('[data-id="contractGUIDeployWithProxyLabel"]') |
||||||
|
.useXpath() |
||||||
|
.waitForElementPresent('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[1]/input') |
||||||
|
.waitForElementPresent('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[2]/input') |
||||||
|
.setValue('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[1]/input', 'Remix') |
||||||
|
.setValue('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[2]/input', "R") |
||||||
|
.useCss() |
||||||
|
.createContract('') |
||||||
|
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)') |
||||||
|
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') |
||||||
|
.click('[data-id="udappNotify-modal-footer-ok-react"]') |
||||||
|
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Deploy Proxy (ERC1967)') |
||||||
|
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') |
||||||
|
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') |
||||||
|
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') |
||||||
|
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') |
||||||
|
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 < 5.0.0 as proxy...', 60000) |
||||||
|
}, |
||||||
|
|
||||||
|
'Should interact with initialized contract to verify parameters #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.getAddressAtPosition(1, (address) => { |
||||||
|
lastProxyAddress = address |
||||||
|
shortenedLastAddress = address.slice(0, 5) + '...' + address.slice(address.length - 5, address.length) |
||||||
|
}) |
||||||
|
.clickInstance(1) |
||||||
|
.perform((done) => { |
||||||
|
browser.testConstantFunction(lastProxyAddress, 'name - call', null, '0:\nstring: Remix').perform(() => { |
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
.perform((done) => { |
||||||
|
browser.testConstantFunction(lastProxyAddress, 'symbol - call', null, '0:\nstring: R').perform(() => { |
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'Should upgrade contract by selecting a previously deployed proxy address from dropdown (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="terminalClearConsole"]')
|
||||||
|
.waitForElementPresent('[data-id="deployAndRunClearInstances"]') |
||||||
|
.click('[data-id="deployAndRunClearInstances"]') |
||||||
|
.openFile('myTokenV2.sol') |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.assert.visible('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.click('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000) |
||||||
|
.clickLaunchIcon('udapp') |
||||||
|
.click('select.udapp_contractNames') |
||||||
|
.click('select.udapp_contractNames option[value=MyTokenV2]') |
||||||
|
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]') |
||||||
|
.click('[data-id="contractGUIUpgradeImplementationLabel"]') |
||||||
|
.waitForElementPresent('[data-id="toggleProxyAddressDropdown"]') |
||||||
|
.click('[data-id="toggleProxyAddressDropdown"]') |
||||||
|
.waitForElementVisible('[data-id="proxy-dropdown-items"]') |
||||||
|
.assert.textContains('[data-id="proxy-dropdown-items"]', shortenedFirstAddress) |
||||||
|
.assert.textContains('[data-id="proxy-dropdown-items"]', shortenedLastAddress) |
||||||
|
.click('[data-id="proxyAddress1"]') |
||||||
|
.createContract('') |
||||||
|
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Update Proxy') |
||||||
|
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') |
||||||
|
.click('[data-id="udappNotify-modal-footer-ok-react"]') |
||||||
|
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Update Proxy (ERC1967)') |
||||||
|
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') |
||||||
|
.click( |
||||||
|
{ |
||||||
|
selector: '[data-id="confirmProxyDeployment-modal-footer-ok-react"]', |
||||||
|
}) |
||||||
|
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') |
||||||
|
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') |
||||||
|
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 < 5.0.0 for the proxy upgrade..', 60000) |
||||||
|
}, |
||||||
|
|
||||||
|
'Should interact with upgraded function in contract MyTokenV2 #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clickInstance(1) |
||||||
|
.perform((done) => { |
||||||
|
browser.testConstantFunction(lastProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => { |
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
'Should upgrade contract by providing proxy address in input field (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.click('*[data-id="terminalClearConsole"]')
|
||||||
|
.waitForElementPresent('[data-id="deployAndRunClearInstances"]') |
||||||
|
.click('[data-id="deployAndRunClearInstances"]') |
||||||
|
.openFile('myTokenV2.sol') |
||||||
|
.clickLaunchIcon('solidity') |
||||||
|
.assert.visible('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.click('[data-id="compilerContainerCompileBtn"]') |
||||||
|
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000) |
||||||
|
.clickLaunchIcon('udapp') |
||||||
|
.click('select.udapp_contractNames') |
||||||
|
.click('select.udapp_contractNames option[value=MyTokenV2]') |
||||||
|
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]') |
||||||
|
.waitForElementPresent('[data-id="toggleProxyAddressDropdown"]') |
||||||
|
.clearValue('[data-id="ERC1967AddressInput"]') |
||||||
|
.setValue('[data-id="ERC1967AddressInput"]', firstProxyAddress) |
||||||
|
.createContract('') |
||||||
|
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Update Proxy') |
||||||
|
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') |
||||||
|
.click('[data-id="udappNotify-modal-footer-ok-react"]') |
||||||
|
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Update Proxy (ERC1967)') |
||||||
|
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') |
||||||
|
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]') |
||||||
|
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]') |
||||||
|
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]') |
||||||
|
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 < 5.0.0 for the proxy upgrade..', 60000) |
||||||
|
}, |
||||||
|
|
||||||
|
'Should interact with upgraded contract through provided proxy address #group1': function (browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.clearConsole() |
||||||
|
.clickInstance(1) |
||||||
|
.perform((done) => { |
||||||
|
browser.testConstantFunction(firstProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => { |
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
'Should debug the call': function(browser: NightwatchBrowser) { |
||||||
|
browser |
||||||
|
.debugTransaction(0) |
||||||
|
.waitForElementVisible({ |
||||||
|
locateStrategy: 'xpath', |
||||||
|
selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"11")]', |
||||||
|
timeout: 60000 |
||||||
|
}) |
||||||
|
.goToVMTraceStep(146) |
||||||
|
.waitForElementContainsText('*[data-id="functionPanel"]', 'version()', 60000)
|
||||||
|
.end() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const sources = [ |
||||||
|
{ |
||||||
|
'myTokenV1.sol': { |
||||||
|
content: ` |
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.4; |
||||||
|
|
||||||
|
import "@openzeppelin/contracts-upgradeable@4.8.3/token/ERC721/ERC721Upgradeable.sol"; |
||||||
|
import "@openzeppelin/contracts-upgradeable@4.8.3/access/OwnableUpgradeable.sol"; |
||||||
|
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/Initializable.sol"; |
||||||
|
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/UUPSUpgradeable.sol"; |
||||||
|
|
||||||
|
contract MyToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable { |
||||||
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
||||||
|
constructor() { |
||||||
|
_disableInitializers(); |
||||||
|
} |
||||||
|
|
||||||
|
function initialize() initializer public { |
||||||
|
__ERC721_init("MyToken", "MTK"); |
||||||
|
__Ownable_init(); |
||||||
|
__UUPSUpgradeable_init(); |
||||||
|
} |
||||||
|
|
||||||
|
function _authorizeUpgrade(address newImplementation) |
||||||
|
internal |
||||||
|
onlyOwner |
||||||
|
override |
||||||
|
{} |
||||||
|
} |
||||||
|
` |
||||||
|
} |
||||||
|
}, { |
||||||
|
'myTokenV2.sol': { |
||||||
|
content: ` |
||||||
|
import "./myTokenV1.sol"; |
||||||
|
|
||||||
|
contract MyTokenV2 is MyToken { |
||||||
|
function version () public view returns (string memory) { |
||||||
|
return "MyTokenV2!"; |
||||||
|
} |
||||||
|
} |
||||||
|
` |
||||||
|
} |
||||||
|
}, { |
||||||
|
'initializeProxy.sol': { |
||||||
|
content: ` |
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.4; |
||||||
|
|
||||||
|
import "@openzeppelin/contracts-upgradeable@4.8.3/token/ERC721/ERC721Upgradeable.sol"; |
||||||
|
import "@openzeppelin/contracts-upgradeable@4.8.3/access/OwnableUpgradeable.sol"; |
||||||
|
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/Initializable.sol"; |
||||||
|
import "@openzeppelin/contracts-upgradeable@4.8.3/proxy/utils/UUPSUpgradeable.sol"; |
||||||
|
|
||||||
|
contract MyInitializedToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable { |
||||||
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
||||||
|
constructor() { |
||||||
|
_disableInitializers(); |
||||||
|
} |
||||||
|
|
||||||
|
function initialize(string memory tokenName, string memory tokenSymbol) initializer public { |
||||||
|
__ERC721_init(tokenName, tokenSymbol); |
||||||
|
__Ownable_init(); |
||||||
|
__UUPSUpgradeable_init(); |
||||||
|
} |
||||||
|
|
||||||
|
function _authorizeUpgrade(address newImplementation) |
||||||
|
internal |
||||||
|
onlyOwner |
||||||
|
override |
||||||
|
{} |
||||||
|
} |
||||||
|
` |
||||||
|
} |
||||||
|
} |
||||||
|
] |
@ -1,105 +1,105 @@ |
|||||||
// 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 |
||||||
addLocalPlugin(this: NightwatchBrowser, profile: Profile & LocationProfile & ExternalProfile): NightwatchBrowser |
addLocalPlugin(this: NightwatchBrowser, profile: Profile & LocationProfile & ExternalProfile): NightwatchBrowser |
||||||
acceptAndRemember (this: NightwatchBrowser, remember: boolean, accept: boolean): NightwatchBrowser |
acceptAndRemember(this: NightwatchBrowser, remember: boolean, accept: boolean): NightwatchBrowser |
||||||
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 |
||||||
} |
} |
||||||
|
|
||||||
export interface NightwatchAPI { |
export interface NightwatchAPI { |
||||||
keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void): NightwatchAPI |
keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void): NightwatchAPI |
||||||
} |
} |
||||||
|
|
||||||
export interface NightwatchContractContent { |
export interface NightwatchContractContent { |
||||||
content: string; |
content: string |
||||||
} |
} |
||||||
|
|
||||||
export interface NightwatchClickFunctionExpectedInput { |
export interface NightwatchClickFunctionExpectedInput { |
||||||
types: string, |
types: string |
||||||
values: string |
values: string |
||||||
} |
} |
||||||
|
|
||||||
export interface NightwatchTestFunctionExpectedInput { |
export interface NightwatchTestFunctionExpectedInput { |
||||||
[key: string]: any |
[key: string]: any |
||||||
} |
} |
||||||
|
|
||||||
export interface NightwatchTestConstantFunctionExpectedInput { |
export interface NightwatchTestConstantFunctionExpectedInput { |
||||||
types: string, |
types: string |
||||||
values: string |
values: string |
||||||
} |
} |
||||||
|
|
||||||
export type NightwatchCheckVariableDebugValue = NightwatchTestFunctionExpectedInput |
export type NightwatchCheckVariableDebugValue = NightwatchTestFunctionExpectedInput |
||||||
} |
} |
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,144 +1,174 @@ |
|||||||
import { RemixApp } from '@remix-ui/app' |
import {RemixApp} from '@remix-ui/app' |
||||||
import React, { useEffect, useRef, useState } from 'react' |
import React, {useEffect, useRef, useState} from 'react' |
||||||
import { render } from 'react-dom' |
import {render} from 'react-dom' |
||||||
import * as packageJson from '../../../../../package.json' |
import * as packageJson from '../../../../../package.json' |
||||||
import { fileSystem, fileSystems } from '../files/fileSystem' |
import {fileSystem, fileSystems} from '../files/fileSystem' |
||||||
import { indexedDBFileSystem } from '../files/filesystems/indexedDB' |
import {indexedDBFileSystem} from '../files/filesystems/indexedDB' |
||||||
import { localStorageFS } from '../files/filesystems/localStorage' |
import {localStorageFS} from '../files/filesystems/localStorage' |
||||||
import { fileSystemUtility, migrationTestData } from '../files/filesystems/fileSystemUtility' |
import {fileSystemUtility, migrationTestData} from '../files/filesystems/fileSystemUtility' |
||||||
import './styles/preload.css' |
import './styles/preload.css' |
||||||
const _paq = window._paq = window._paq || [] |
const _paq = (window._paq = window._paq || []) |
||||||
|
|
||||||
export const Preload = () => { |
export const Preload = () => { |
||||||
|
const [supported, setSupported] = useState<boolean>(true) |
||||||
|
const [error, setError] = useState<boolean>(false) |
||||||
|
const [showDownloader, setShowDownloader] = useState<boolean>(false) |
||||||
|
const remixFileSystems = useRef<fileSystems>(new fileSystems()) |
||||||
|
const remixIndexedDB = useRef<fileSystem>(new indexedDBFileSystem()) |
||||||
|
const localStorageFileSystem = useRef<fileSystem>(new localStorageFS()) |
||||||
|
// url parameters to e2e test the fallbacks and error warnings
|
||||||
|
const testmigrationFallback = useRef<boolean>( |
||||||
|
window.location.hash.includes('e2e_testmigration_fallback=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:' |
||||||
|
) |
||||||
|
const testmigrationResult = useRef<boolean>( |
||||||
|
window.location.hash.includes('e2e_testmigration=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:' |
||||||
|
) |
||||||
|
const testBlockStorage = useRef<boolean>( |
||||||
|
window.location.hash.includes('e2e_testblock_storage=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:' |
||||||
|
) |
||||||
|
|
||||||
const [supported, setSupported] = useState<boolean>(true) |
function loadAppComponent() { |
||||||
const [error, setError] = useState<boolean>(false) |
import('../../app') |
||||||
const [showDownloader, setShowDownloader] = useState<boolean>(false) |
.then((AppComponent) => { |
||||||
const remixFileSystems = useRef<fileSystems>(new fileSystems()) |
const appComponent = new AppComponent.default() |
||||||
const remixIndexedDB = useRef<fileSystem>(new indexedDBFileSystem()) |
appComponent.run().then(() => { |
||||||
const localStorageFileSystem = useRef<fileSystem>(new localStorageFS()) |
render( |
||||||
// url parameters to e2e test the fallbacks and error warnings
|
<> |
||||||
const testmigrationFallback = useRef<boolean>(window.location.hash.includes('e2e_testmigration_fallback=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:') |
<RemixApp app={appComponent} /> |
||||||
const testmigrationResult = useRef<boolean>(window.location.hash.includes('e2e_testmigration=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:') |
</>, |
||||||
const testBlockStorage = useRef<boolean>(window.location.hash.includes('e2e_testblock_storage=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:') |
document.getElementById('root') |
||||||
|
) |
||||||
function loadAppComponent() { |
|
||||||
import('../../app').then((AppComponent) => { |
|
||||||
const appComponent = new AppComponent.default() |
|
||||||
appComponent.run().then(() => { |
|
||||||
render( |
|
||||||
<> |
|
||||||
<RemixApp app={appComponent} /> |
|
||||||
</>, |
|
||||||
document.getElementById('root') |
|
||||||
) |
|
||||||
}) |
|
||||||
}).catch(err => { |
|
||||||
_paq.push(['trackEvent', 'Preload', 'error', err && err.message]) |
|
||||||
console.error('Error loading Remix:', err) |
|
||||||
setError(true) |
|
||||||
}) |
}) |
||||||
} |
}) |
||||||
|
.catch((err) => { |
||||||
|
_paq.push(['trackEvent', 'Preload', 'error', err && err.message]) |
||||||
|
console.error('Error loading Remix:', err) |
||||||
|
setError(true) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
const downloadBackup = async () => { |
const downloadBackup = async () => { |
||||||
setShowDownloader(false) |
setShowDownloader(false) |
||||||
const fsUtility = new fileSystemUtility() |
const fsUtility = new fileSystemUtility() |
||||||
await fsUtility.downloadBackup(remixFileSystems.current.fileSystems['localstorage']) |
await fsUtility.downloadBackup(remixFileSystems.current.fileSystems['localstorage']) |
||||||
await migrateAndLoad() |
await migrateAndLoad() |
||||||
} |
} |
||||||
|
|
||||||
const migrateAndLoad = async () => { |
const migrateAndLoad = async () => { |
||||||
setShowDownloader(false) |
setShowDownloader(false) |
||||||
const fsUtility = new fileSystemUtility() |
const fsUtility = new fileSystemUtility() |
||||||
const migrationResult = await fsUtility.migrate(localStorageFileSystem.current, remixIndexedDB.current) |
const migrationResult = await fsUtility.migrate(localStorageFileSystem.current, remixIndexedDB.current) |
||||||
_paq.push(['trackEvent', 'Migrate', 'result', migrationResult?'success' : 'fail']) |
_paq.push(['trackEvent', 'Migrate', 'result', migrationResult ? 'success' : 'fail']) |
||||||
await setFileSystems() |
await setFileSystems() |
||||||
} |
} |
||||||
|
|
||||||
const setFileSystems = async() => { |
const setFileSystems = async () => { |
||||||
const fsLoaded = await remixFileSystems.current.setFileSystem([(testmigrationFallback.current || testBlockStorage.current)? null: remixIndexedDB.current, testBlockStorage.current? null:localStorageFileSystem.current]) |
const fsLoaded = await remixFileSystems.current.setFileSystem([ |
||||||
if (fsLoaded) { |
testmigrationFallback.current || testBlockStorage.current ? null : remixIndexedDB.current, |
||||||
console.log(fsLoaded.name + ' activated') |
testBlockStorage.current ? null : localStorageFileSystem.current |
||||||
_paq.push(['trackEvent', 'Storage', 'activate', fsLoaded.name]) |
]) |
||||||
loadAppComponent() |
if (fsLoaded) { |
||||||
} else { |
console.log(fsLoaded.name + ' activated') |
||||||
_paq.push(['trackEvent', 'Storage', 'error', 'no supported storage']) |
_paq.push(['trackEvent', 'Storage', 'activate', fsLoaded.name]) |
||||||
setSupported(false) |
loadAppComponent() |
||||||
} |
} else { |
||||||
|
_paq.push(['trackEvent', 'Storage', 'error', 'no supported storage']) |
||||||
|
setSupported(false) |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
const testmigration = async() => {
|
const testmigration = async () => { |
||||||
if (testmigrationResult.current) { |
if (testmigrationResult.current) { |
||||||
const fsUtility = new fileSystemUtility() |
const fsUtility = new fileSystemUtility() |
||||||
fsUtility.populateWorkspace(migrationTestData, remixFileSystems.current.fileSystems['localstorage'].fs) |
fsUtility.populateWorkspace(migrationTestData, remixFileSystems.current.fileSystems['localstorage'].fs) |
||||||
} |
|
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
useEffect(() => { |
useEffect(() => { |
||||||
async function loadStorage() { |
async function loadStorage() { |
||||||
await remixFileSystems.current.addFileSystem(remixIndexedDB.current) || _paq.push(['trackEvent', 'Storage', 'error', 'indexedDB not supported']) |
;(await remixFileSystems.current.addFileSystem(remixIndexedDB.current)) || _paq.push(['trackEvent', 'Storage', 'error', 'indexedDB not supported']) |
||||||
await remixFileSystems.current.addFileSystem(localStorageFileSystem.current) || _paq.push(['trackEvent', 'Storage', 'error', 'localstorage not supported']) |
;(await remixFileSystems.current.addFileSystem(localStorageFileSystem.current)) || _paq.push(['trackEvent', 'Storage', 'error', 'localstorage not supported']) |
||||||
await testmigration() |
await testmigration() |
||||||
remixIndexedDB.current.loaded && await remixIndexedDB.current.checkWorkspaces() |
remixIndexedDB.current.loaded && (await remixIndexedDB.current.checkWorkspaces()) |
||||||
localStorageFileSystem.current.loaded && await localStorageFileSystem.current.checkWorkspaces() |
localStorageFileSystem.current.loaded && (await localStorageFileSystem.current.checkWorkspaces()) |
||||||
remixIndexedDB.current.loaded && ( (remixIndexedDB.current.hasWorkSpaces || !localStorageFileSystem.current.hasWorkSpaces)? await setFileSystems():setShowDownloader(true)) |
remixIndexedDB.current.loaded && (remixIndexedDB.current.hasWorkSpaces || !localStorageFileSystem.current.hasWorkSpaces ? await setFileSystems() : setShowDownloader(true)) |
||||||
!remixIndexedDB.current.loaded && await setFileSystems() |
!remixIndexedDB.current.loaded && (await setFileSystems()) |
||||||
} |
} |
||||||
loadStorage() |
loadStorage() |
||||||
}, []) |
}, []) |
||||||
|
|
||||||
return <> |
return ( |
||||||
<div className='preload-container'> |
<> |
||||||
<div className='preload-logo pb-4'> |
<div className="preload-container"> |
||||||
{logo} |
<div className="preload-logo pb-4"> |
||||||
<div className="info-secondary splash"> |
{logo} |
||||||
REMIX IDE |
<div className="info-secondary splash"> |
||||||
<br /> |
REMIX IDE |
||||||
<span className='version'> v{packageJson.version}</span> |
<br /> |
||||||
</div> |
<span className="version"> v{packageJson.version}</span> |
||||||
</div> |
</div> |
||||||
{!supported ? |
|
||||||
<div className='preload-info-container alert alert-warning'> |
|
||||||
Your browser does not support any of the filesystems required by Remix. |
|
||||||
Either change the settings in your browser or use a supported browser. |
|
||||||
</div> : null} |
|
||||||
{error ? |
|
||||||
<div className='preload-info-container alert alert-danger text-left'> |
|
||||||
An unknown error has occurred while loading the application.<br></br> |
|
||||||
Doing a hard refresh might fix this issue:<br></br> |
|
||||||
<div className='pt-2'> |
|
||||||
Windows:<br></br> |
|
||||||
- Chrome: CTRL + F5 or CTRL + Reload Button<br></br> |
|
||||||
- Firefox: CTRL + SHIFT + R or CTRL + F5<br></br> |
|
||||||
</div> |
|
||||||
<div className='pt-2'> |
|
||||||
MacOS:<br></br> |
|
||||||
- Chrome & FireFox: CMD + SHIFT + R or SHIFT + Reload Button<br></br> |
|
||||||
</div> |
|
||||||
<div className='pt-2'> |
|
||||||
Linux:<br></br> |
|
||||||
- Chrome & FireFox: CTRL + SHIFT + R<br></br> |
|
||||||
</div> |
|
||||||
</div> : null} |
|
||||||
{showDownloader ? |
|
||||||
<div className='preload-info-container alert alert-info'> |
|
||||||
This app will be updated now. Please download a backup of your files now to make sure you don't lose your work. |
|
||||||
<br></br> |
|
||||||
You don't need to do anything else, your files will be available when the app loads. |
|
||||||
<div onClick={async () => { await downloadBackup() }} data-id='downloadbackup-btn' className='btn btn-primary mt-1'>download backup</div> |
|
||||||
<div onClick={async () => { await migrateAndLoad() }} data-id='skipbackup-btn' className='btn btn-primary mt-1'>skip backup</div> |
|
||||||
</div> : null} |
|
||||||
{(supported && !error && !showDownloader) ? |
|
||||||
<div> |
|
||||||
<i className="fas fa-spinner fa-spin fa-2x"></i> |
|
||||||
</div> : null} |
|
||||||
</div> |
</div> |
||||||
|
{!supported ? ( |
||||||
|
<div className="preload-info-container alert alert-warning"> |
||||||
|
Your browser does not support any of the filesystems required by Remix. Either change the settings in your browser or use a supported browser. |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
{error ? ( |
||||||
|
<div className="preload-info-container alert alert-danger text-left"> |
||||||
|
An unknown error has occurred while loading the application. |
||||||
|
<br></br> |
||||||
|
Doing a hard refresh might fix this issue:<br></br> |
||||||
|
<div className="pt-2"> |
||||||
|
Windows:<br></br>- Chrome: CTRL + F5 or CTRL + Reload Button |
||||||
|
<br></br>- Firefox: CTRL + SHIFT + R or CTRL + F5<br></br> |
||||||
|
</div> |
||||||
|
<div className="pt-2"> |
||||||
|
MacOS:<br></br>- Chrome & FireFox: CMD + SHIFT + R or SHIFT + Reload Button<br></br> |
||||||
|
</div> |
||||||
|
<div className="pt-2"> |
||||||
|
Linux:<br></br>- Chrome & FireFox: CTRL + SHIFT + R<br></br> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
{showDownloader ? ( |
||||||
|
<div className="preload-info-container alert alert-info"> |
||||||
|
This app will be updated now. Please download a backup of your files now to make sure you don't lose your work. |
||||||
|
<br></br> |
||||||
|
You don't need to do anything else, your files will be available when the app loads. |
||||||
|
<div |
||||||
|
onClick={async () => { |
||||||
|
await downloadBackup() |
||||||
|
}} |
||||||
|
data-id="downloadbackup-btn" |
||||||
|
className="btn btn-primary mt-1" |
||||||
|
> |
||||||
|
download backup |
||||||
|
</div> |
||||||
|
<div |
||||||
|
onClick={async () => { |
||||||
|
await migrateAndLoad() |
||||||
|
}} |
||||||
|
data-id="skipbackup-btn" |
||||||
|
className="btn btn-primary mt-1" |
||||||
|
> |
||||||
|
skip backup |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
{supported && !error && !showDownloader ? ( |
||||||
|
<div> |
||||||
|
<i className="fas fa-spinner fa-spin fa-2x"></i> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
</div> |
||||||
</> |
</> |
||||||
|
) |
||||||
} |
} |
||||||
|
|
||||||
|
const logo = ( |
||||||
const logo = <svg id="Ebene_2" data-name="Ebene 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105 100"> |
<svg id="Ebene_2" data-name="Ebene 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105 100"> |
||||||
<path d="M91.84,35a.09.09,0,0,1-.1-.07,41,41,0,0,0-79.48,0,.09.09,0,0,1-.1.07C9.45,35,1,35.35,1,42.53c0,8.56,1,16,6,20.32,2.16,1.85,5.81,2.3,9.27,2.22a44.4,44.4,0,0,0,6.45-.68.09.09,0,0,0,.06-.15A34.81,34.81,0,0,1,17,45c0-.1,0-.21,0-.31a35,35,0,0,1,70,0c0,.1,0,.21,0,.31a34.81,34.81,0,0,1-5.78,19.24.09.09,0,0,0,.06.15,44.4,44.4,0,0,0,6.45.68c3.46.08,7.11-.37,9.27-2.22,5-4.27,6-11.76,6-20.32C103,35.35,94.55,35,91.84,35Z" /> |
<path d="M91.84,35a.09.09,0,0,1-.1-.07,41,41,0,0,0-79.48,0,.09.09,0,0,1-.1.07C9.45,35,1,35.35,1,42.53c0,8.56,1,16,6,20.32,2.16,1.85,5.81,2.3,9.27,2.22a44.4,44.4,0,0,0,6.45-.68.09.09,0,0,0,.06-.15A34.81,34.81,0,0,1,17,45c0-.1,0-.21,0-.31a35,35,0,0,1,70,0c0,.1,0,.21,0,.31a34.81,34.81,0,0,1-5.78,19.24.09.09,0,0,0,.06.15,44.4,44.4,0,0,0,6.45.68c3.46.08,7.11-.37,9.27-2.22,5-4.27,6-11.76,6-20.32C103,35.35,94.55,35,91.84,35Z" /> |
||||||
<path d="M52,74,25.4,65.13a.1.1,0,0,0-.1.17L51.93,91.93a.1.1,0,0,0,.14,0L78.7,65.3a.1.1,0,0,0-.1-.17L52,74A.06.06,0,0,1,52,74Z" /> |
<path d="M52,74,25.4,65.13a.1.1,0,0,0-.1.17L51.93,91.93a.1.1,0,0,0,.14,0L78.7,65.3a.1.1,0,0,0-.1-.17L52,74A.06.06,0,0,1,52,74Z" /> |
||||||
<path d="M75.68,46.9,82,45a.09.09,0,0,0,.08-.09,29.91,29.91,0,0,0-.87-6.94.11.11,0,0,0-.09-.08l-6.43-.58a.1.1,0,0,1-.06-.18l4.78-4.18a.13.13,0,0,0,0-.12,30.19,30.19,0,0,0-3.65-6.07.09.09,0,0,0-.11,0l-5.91,2a.1.1,0,0,1-.12-.14L72.19,23a.11.11,0,0,0,0-.12,29.86,29.86,0,0,0-5.84-4.13.09.09,0,0,0-.11,0l-4.47,4.13a.1.1,0,0,1-.17-.07l.09-6a.1.1,0,0,0-.07-.1,30.54,30.54,0,0,0-7-1.47.1.1,0,0,0-.1.07l-2.38,5.54a.1.1,0,0,1-.18,0l-2.37-5.54a.11.11,0,0,0-.11-.06,30,30,0,0,0-7,1.48.12.12,0,0,0-.07.1l.08,6.05a.09.09,0,0,1-.16.07L37.8,18.76a.11.11,0,0,0-.12,0,29.75,29.75,0,0,0-5.83,4.13.11.11,0,0,0,0,.12l2.59,5.6a.11.11,0,0,1-.13.14l-5.9-2a.11.11,0,0,0-.12,0,30.23,30.23,0,0,0-3.62,6.08.11.11,0,0,0,0,.12l4.79,4.19a.1.1,0,0,1-.06.17L23,37.91a.1.1,0,0,0-.09.07A29.9,29.9,0,0,0,22,44.92a.1.1,0,0,0,.07.1L28.4,47a.1.1,0,0,1,0,.18l-5.84,3.26a.16.16,0,0,0,0,.11,30.17,30.17,0,0,0,2.1,6.76c.32.71.67,1.4,1,2.08a.1.1,0,0,0,.06,0L52,68.16H52l26.34-8.78a.1.1,0,0,0,.06-.05,30.48,30.48,0,0,0,3.11-8.88.1.1,0,0,0-.05-.11l-5.83-3.26A.1.1,0,0,1,75.68,46.9Z" /> |
<path d="M75.68,46.9,82,45a.09.09,0,0,0,.08-.09,29.91,29.91,0,0,0-.87-6.94.11.11,0,0,0-.09-.08l-6.43-.58a.1.1,0,0,1-.06-.18l4.78-4.18a.13.13,0,0,0,0-.12,30.19,30.19,0,0,0-3.65-6.07.09.09,0,0,0-.11,0l-5.91,2a.1.1,0,0,1-.12-.14L72.19,23a.11.11,0,0,0,0-.12,29.86,29.86,0,0,0-5.84-4.13.09.09,0,0,0-.11,0l-4.47,4.13a.1.1,0,0,1-.17-.07l.09-6a.1.1,0,0,0-.07-.1,30.54,30.54,0,0,0-7-1.47.1.1,0,0,0-.1.07l-2.38,5.54a.1.1,0,0,1-.18,0l-2.37-5.54a.11.11,0,0,0-.11-.06,30,30,0,0,0-7,1.48.12.12,0,0,0-.07.1l.08,6.05a.09.09,0,0,1-.16.07L37.8,18.76a.11.11,0,0,0-.12,0,29.75,29.75,0,0,0-5.83,4.13.11.11,0,0,0,0,.12l2.59,5.6a.11.11,0,0,1-.13.14l-5.9-2a.11.11,0,0,0-.12,0,30.23,30.23,0,0,0-3.62,6.08.11.11,0,0,0,0,.12l4.79,4.19a.1.1,0,0,1-.06.17L23,37.91a.1.1,0,0,0-.09.07A29.9,29.9,0,0,0,22,44.92a.1.1,0,0,0,.07.1L28.4,47a.1.1,0,0,1,0,.18l-5.84,3.26a.16.16,0,0,0,0,.11,30.17,30.17,0,0,0,2.1,6.76c.32.71.67,1.4,1,2.08a.1.1,0,0,0,.06,0L52,68.16H52l26.34-8.78a.1.1,0,0,0,.06-.05,30.48,30.48,0,0,0,3.11-8.88.1.1,0,0,0-.05-.11l-5.83-3.26A.1.1,0,0,1,75.68,46.9Z" /> |
||||||
</svg> |
</svg> |
||||||
|
) |
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue