commit
d15c3b3f2d
@ -1,4 +1,4 @@ |
||||
#!/usr/bin/env sh |
||||
. "$(dirname -- "$0")/_/husky.sh" |
||||
|
||||
yarn lint-staged |
||||
|
||||
|
@ -1,3 +0,0 @@ |
||||
{ |
||||
"*.{tsx,ts,js,jsx,mjs,cjs}": ["prettier --write","eslint --fix"] |
||||
} |
@ -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 = { |
||||
// all mainnet
|
||||
1: "https://api.etherscan.io/api", |
||||
56: "https://api.bscscan.com/api", |
||||
137: "https://api.polygonscan.com/api", |
||||
250: "https://api.ftmscan.com/api", |
||||
42161: "https://api.arbiscan.io/api", |
||||
43114: "https://api.snowtrace.io/api", |
||||
1285: "https://api-moonriver.moonscan.io/api", |
||||
1284: "https://api-moonbeam.moonscan.io/api", |
||||
25: "https://api.cronoscan.com/api", |
||||
199: "https://api.bttcscan.com/api", |
||||
10: "https://api-optimistic.etherscan.io/api", |
||||
42220: "https://api.celoscan.io/api", |
||||
288: "https://api.bobascan.com/api", |
||||
100: "https://api.gnosisscan.io/api", |
||||
1101: "https://api-zkevm.polygonscan.com/api", |
||||
// all mainnet
|
||||
1: 'https://api.etherscan.io/api', |
||||
56: 'https://api.bscscan.com/api', |
||||
137: 'https://api.polygonscan.com/api', |
||||
250: 'https://api.ftmscan.com/api', |
||||
42161: 'https://api.arbiscan.io/api', |
||||
43114: 'https://api.snowtrace.io/api', |
||||
1285: 'https://api-moonriver.moonscan.io/api', |
||||
1284: 'https://api-moonbeam.moonscan.io/api', |
||||
25: 'https://api.cronoscan.com/api', |
||||
199: 'https://api.bttcscan.com/api', |
||||
10: 'https://api-optimistic.etherscan.io/api', |
||||
42220: 'https://api.celoscan.io/api', |
||||
288: 'https://api.bobascan.com/api', |
||||
100: 'https://api.gnosisscan.io/api', |
||||
1101: 'https://api-zkevm.polygonscan.com/api', |
||||
59144: 'https://api.lineascan.build/api', |
||||
|
||||
// all testnet
|
||||
5: "https://api-goerli.etherscan.io/api", |
||||
11155111: "https://api-sepolia.etherscan.io/api", |
||||
97: "https://api-testnet.bscscan.com/api", |
||||
80001: "https://api-testnet.polygonscan.com/api", |
||||
4002: "https://api-testnet.ftmscan.com/api", |
||||
421611: "https://api-testnet.arbiscan.io/api", |
||||
42170: "https://api-nova.arbiscan.io/api", |
||||
43113: "https://api-testnet.snowtrace.io/api", |
||||
1287: "https://api-moonbase.moonscan.io/api", |
||||
338: "https://api-testnet.cronoscan.com/api", |
||||
1028: "https://api-testnet.bttcscan.com/api", |
||||
420: "https://api-goerli-optimistic.etherscan.io/api", |
||||
44787: "https://api-alfajores.celoscan.io/api", |
||||
2888: "https://api-testnet.bobascan.com/api", |
||||
84531: "https://api-goerli.basescan.org/api", |
||||
1442: "https://api-testnet-zkevm.polygonscan.com/api" |
||||
} |
||||
// all testnet
|
||||
5: 'https://api-goerli.etherscan.io/api', |
||||
11155111: 'https://api-sepolia.etherscan.io/api', |
||||
97: 'https://api-testnet.bscscan.com/api', |
||||
80001: 'https://api-testnet.polygonscan.com/api', |
||||
4002: 'https://api-testnet.ftmscan.com/api', |
||||
421611: 'https://api-testnet.arbiscan.io/api', |
||||
42170: 'https://api-nova.arbiscan.io/api', |
||||
43113: 'https://api-testnet.snowtrace.io/api', |
||||
1287: 'https://api-moonbase.moonscan.io/api', |
||||
338: 'https://api-testnet.cronoscan.com/api', |
||||
1028: 'https://api-testnet.bttcscan.com/api', |
||||
420: 'https://api-goerli-optimistic.etherscan.io/api', |
||||
44787: 'https://api-alfajores.celoscan.io/api', |
||||
2888: 'https://api-testnet.bobascan.com/api', |
||||
84531: 'https://api-goerli.basescan.org/api', |
||||
1442: 'https://api-testnet-zkevm.polygonscan.com/api', |
||||
59140: 'https://api-testnet.lineascan.build/api', |
||||
} |
||||
|
@ -1,105 +1,105 @@ |
||||
// Merge custom command types with nightwatch types
|
||||
/* eslint-disable no-use-before-define */ |
||||
import { NightwatchBrowser } from 'nightwatch' // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
export type callbackCheckVerifyCallReturnValue = (values: string[]) => { message: string, pass: boolean } |
||||
import {NightwatchBrowser} from 'nightwatch' // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
export type callbackCheckVerifyCallReturnValue = (values: string[]) => {message: string; pass: boolean} |
||||
|
||||
declare module 'nightwatch' { |
||||
export interface NightwatchCustomCommands { |
||||
clickLaunchIcon(icon: string): NightwatchBrowser, |
||||
switchBrowserTab(index: number): NightwatchBrowser, |
||||
scrollAndClick(target: string): NightwatchBrowser, |
||||
scrollInto(target: string): NightwatchBrowser, |
||||
testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser, |
||||
setEditorValue(value: string, callback?: () => void): NightwatchBrowser, |
||||
addFile(name: string, content: NightwatchContractContent): NightwatchBrowser, |
||||
verifyContracts(compiledContractNames: string[], opts?: { wait: number, version?: string, runs?: string }): NightwatchBrowser, |
||||
selectAccount(account?: string): NightwatchBrowser, |
||||
clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser, |
||||
testFunction(txHash: string, expectedInput: NightwatchTestFunctionExpectedInput): NightwatchBrowser, |
||||
goToVMTraceStep(step: number, incr?: number): NightwatchBrowser, |
||||
checkVariableDebug(id: string, debugValue: NightwatchCheckVariableDebugValue): NightwatchBrowser, |
||||
addAtAddressInstance(address: string, isValidFormat: boolean, isValidChecksum: boolean, isAbi?: boolean): NightwatchBrowser, |
||||
modalFooterOKClick(id?: string): NightwatchBrowser, |
||||
clickInstance(index: number): NightwatchBrowser, |
||||
journalLastChildIncludes(val: string): NightwatchBrowser, |
||||
executeScriptInTerminal(script: string): NightwatchBrowser, |
||||
clearEditableContent(cssSelector: string): NightwatchBrowser, |
||||
journalChildIncludes(val: string, opts = { shouldHaveOnlyOneOccurence: boolean }): NightwatchBrowser, |
||||
debugTransaction(index: number): NightwatchBrowser, |
||||
checkElementStyle(cssSelector: string, styleProperty: string, expectedResult: string): NightwatchBrowser, |
||||
openFile(name: string): NightwatchBrowser, |
||||
refreshPage(): NightwatchBrowser, |
||||
verifyLoad(): NightwatchBrowser, |
||||
renamePath(path: string, newFileName: string, renamedPath: string): NightwatchBrowser, |
||||
rightClickCustom(cssSelector: string): NightwatchBrowser, |
||||
scrollToLine(line: number): NightwatchBrowser, |
||||
waitForElementContainsText(id: string, value: string, timeout?: number): NightwatchBrowser, |
||||
getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser, |
||||
modalFooterCancelClick(id?: string): NightwatchBrowser, |
||||
selectContract(contractName: string): NightwatchBrowser, |
||||
createContract(inputParams: string): NightwatchBrowser, |
||||
getAddressAtPosition(index: number, cb: (pos: string) => void): NightwatchBrowser, |
||||
testConstantFunction(address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser, |
||||
getEditorValue(callback: (content: string) => void): NightwatchBrowser, |
||||
getInstalledPlugins(cb: (plugins: string[]) => void): NightwatchBrowser, |
||||
verifyCallReturnValue(address: string, checks: string[] | callbackCheckVerifyCallReturnValue): NightwatchBrowser, |
||||
testEditorValue(testvalue: string): NightwatchBrowser, |
||||
removeFile(path: string, workspace: string): NightwatchBrowser, |
||||
switchBrowserWindow(url: string, windowName: string, cb: (browser: NightwatchBrowser, window?: NightwatchCallbackResult<Window>) => void): NightwatchBrowser, |
||||
setupMetamask(passphrase: string, password: string): NightwatchBrowser, |
||||
signMessage(msg: string, callback: (hash: { value: string }, signature: { value: string }) => void): NightwatchBrowser, |
||||
setSolidityCompilerVersion(version: string): NightwatchBrowser, |
||||
clickElementAtPosition(cssSelector: string, index: number, opt?: { forceSelectIfUnselected: boolean }): NightwatchBrowser, |
||||
notContainsText(cssSelector: string, text: string): NightwatchBrowser, |
||||
sendLowLevelTx(address: string, value: string, callData: string): NightwatchBrowser, |
||||
journalLastChild(val: string): NightwatchBrowser, |
||||
checkTerminalFilter(filter: string, test: string): NightwatchBrowser, |
||||
noWorkerErrorFor(version: string): NightwatchBrowser, |
||||
validateValueInput(selector: string, valueTosSet: string, expectedValue: string): NightwatchBrowser |
||||
checkAnnotations(type: string, line: number): NightwatchBrowser |
||||
checkAnnotationsNotPresent(type: string): NightwatchBrowser |
||||
getLastTransactionHash(callback: (hash: string) => void) |
||||
currentWorkspaceIs(name: string): NightwatchBrowser |
||||
addLocalPlugin(this: NightwatchBrowser, profile: Profile & LocationProfile & ExternalProfile): NightwatchBrowser |
||||
acceptAndRemember (this: NightwatchBrowser, remember: boolean, accept: boolean): NightwatchBrowser |
||||
clearConsole (this: NightwatchBrowser): NightwatchBrowser |
||||
clearTransactions (this: NightwatchBrowser): NightwatchBrowser |
||||
getBrowserLogs (this: NightwatchBrowser): NightwatchBrowser |
||||
currentSelectedFileIs (name: string): NightwatchBrowser, |
||||
switchWorkspace: (workspaceName: string) => NightwatchBrowser |
||||
switchEnvironment: (provider: string) => NightwatchBrowser |
||||
connectToExternalHttpProvider: (url: string, identifier: string) => NightwatchBrowser |
||||
} |
||||
export interface NightwatchCustomCommands { |
||||
clickLaunchIcon(icon: string): NightwatchBrowser |
||||
switchBrowserTab(index: number): NightwatchBrowser |
||||
scrollAndClick(target: string): NightwatchBrowser |
||||
scrollInto(target: string): NightwatchBrowser |
||||
testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser |
||||
setEditorValue(value: string, callback?: () => void): NightwatchBrowser |
||||
addFile(name: string, content: NightwatchContractContent): NightwatchBrowser |
||||
verifyContracts(compiledContractNames: string[], opts?: {wait: number; version?: string; runs?: string}): NightwatchBrowser |
||||
selectAccount(account?: string): NightwatchBrowser |
||||
clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser |
||||
testFunction(txHash: string, expectedInput: NightwatchTestFunctionExpectedInput): NightwatchBrowser |
||||
goToVMTraceStep(step: number, incr?: number): NightwatchBrowser |
||||
checkVariableDebug(id: string, debugValue: NightwatchCheckVariableDebugValue): NightwatchBrowser |
||||
addAtAddressInstance(address: string, isValidFormat: boolean, isValidChecksum: boolean, isAbi?: boolean): NightwatchBrowser |
||||
modalFooterOKClick(id?: string): NightwatchBrowser |
||||
clickInstance(index: number): NightwatchBrowser |
||||
journalLastChildIncludes(val: string): NightwatchBrowser |
||||
executeScriptInTerminal(script: string): NightwatchBrowser |
||||
clearEditableContent(cssSelector: string): NightwatchBrowser |
||||
journalChildIncludes(val: string, opts = {shouldHaveOnlyOneOccurence: boolean}): NightwatchBrowser |
||||
debugTransaction(index: number): NightwatchBrowser |
||||
checkElementStyle(cssSelector: string, styleProperty: string, expectedResult: string): NightwatchBrowser |
||||
openFile(name: string): NightwatchBrowser |
||||
refreshPage(): NightwatchBrowser |
||||
verifyLoad(): NightwatchBrowser |
||||
renamePath(path: string, newFileName: string, renamedPath: string): NightwatchBrowser |
||||
rightClickCustom(cssSelector: string): NightwatchBrowser |
||||
scrollToLine(line: number): NightwatchBrowser |
||||
waitForElementContainsText(id: string, value: string, timeout?: number): NightwatchBrowser |
||||
getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser |
||||
modalFooterCancelClick(id?: string): NightwatchBrowser |
||||
selectContract(contractName: string): NightwatchBrowser |
||||
createContract(inputParams: string): NightwatchBrowser |
||||
getAddressAtPosition(index: number, cb: (pos: string) => void): NightwatchBrowser |
||||
testConstantFunction(address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser |
||||
getEditorValue(callback: (content: string) => void): NightwatchBrowser |
||||
getInstalledPlugins(cb: (plugins: string[]) => void): NightwatchBrowser |
||||
verifyCallReturnValue(address: string, checks: string[] | callbackCheckVerifyCallReturnValue): NightwatchBrowser |
||||
testEditorValue(testvalue: string): NightwatchBrowser |
||||
removeFile(path: string, workspace: string): NightwatchBrowser |
||||
switchBrowserWindow(url: string, windowName: string, cb: (browser: NightwatchBrowser, window?: NightwatchCallbackResult<Window>) => void): NightwatchBrowser |
||||
setupMetamask(passphrase: string, password: string): NightwatchBrowser |
||||
signMessage(msg: string, callback: (hash: {value: string}, signature: {value: string}) => void): NightwatchBrowser |
||||
setSolidityCompilerVersion(version: string): NightwatchBrowser |
||||
clickElementAtPosition(cssSelector: string, index: number, opt?: {forceSelectIfUnselected: boolean}): NightwatchBrowser |
||||
notContainsText(cssSelector: string, text: string): NightwatchBrowser |
||||
sendLowLevelTx(address: string, value: string, callData: string): NightwatchBrowser |
||||
journalLastChild(val: string): NightwatchBrowser |
||||
checkTerminalFilter(filter: string, test: string): NightwatchBrowser |
||||
noWorkerErrorFor(version: string): NightwatchBrowser |
||||
validateValueInput(selector: string, valueTosSet: string, expectedValue: string): NightwatchBrowser |
||||
checkAnnotations(type: string): NightwatchBrowser |
||||
checkAnnotationsNotPresent(type: string): NightwatchBrowser |
||||
getLastTransactionHash(callback: (hash: string) => void) |
||||
currentWorkspaceIs(name: string): NightwatchBrowser |
||||
addLocalPlugin(this: NightwatchBrowser, profile: Profile & LocationProfile & ExternalProfile): NightwatchBrowser |
||||
acceptAndRemember(this: NightwatchBrowser, remember: boolean, accept: boolean): NightwatchBrowser |
||||
clearConsole(this: NightwatchBrowser): NightwatchBrowser |
||||
clearTransactions(this: NightwatchBrowser): NightwatchBrowser |
||||
getBrowserLogs(this: NightwatchBrowser): NightwatchBrowser |
||||
currentSelectedFileIs(name: string): NightwatchBrowser |
||||
switchWorkspace: (workspaceName: string) => NightwatchBrowser |
||||
switchEnvironment: (provider: string) => NightwatchBrowser |
||||
connectToExternalHttpProvider: (url: string, identifier: string) => NightwatchBrowser |
||||
} |
||||
|
||||
export interface NightwatchBrowser { |
||||
api: this, |
||||
emit: (status: string) => void, |
||||
fullscreenWindow: (result?: any) => this, |
||||
keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void): NightwatchBrowser, |
||||
sendKeys: (selector: string, inputValue: string | string[], callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void) => NightwatchBrowser |
||||
} |
||||
export interface NightwatchBrowser { |
||||
api: this |
||||
emit: (status: string) => void |
||||
fullscreenWindow: (result?: any) => this |
||||
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 |
||||
} |
||||
|
||||
export interface NightwatchAPI { |
||||
keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void): NightwatchAPI |
||||
} |
||||
export interface NightwatchAPI { |
||||
keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult<void>) => void): NightwatchAPI |
||||
} |
||||
|
||||
export interface NightwatchContractContent { |
||||
content: string; |
||||
} |
||||
export interface NightwatchContractContent { |
||||
content: string |
||||
} |
||||
|
||||
export interface NightwatchClickFunctionExpectedInput { |
||||
types: string, |
||||
values: string |
||||
} |
||||
export interface NightwatchClickFunctionExpectedInput { |
||||
types: string |
||||
values: string |
||||
} |
||||
|
||||
export interface NightwatchTestFunctionExpectedInput { |
||||
[key: string]: any |
||||
} |
||||
export interface NightwatchTestFunctionExpectedInput { |
||||
[key: string]: any |
||||
} |
||||
|
||||
export interface NightwatchTestConstantFunctionExpectedInput { |
||||
types: string, |
||||
values: string |
||||
} |
||||
export interface NightwatchTestConstantFunctionExpectedInput { |
||||
types: string |
||||
values: string |
||||
} |
||||
|
||||
export type NightwatchCheckVariableDebugValue = NightwatchTestFunctionExpectedInput |
||||
export type NightwatchCheckVariableDebugValue = NightwatchTestFunctionExpectedInput |
||||
} |
||||
|
@ -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 |
||||
} |
||||
} |
@ -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/' |
||||
]
|
||||
) |
||||
} |
||||
} |
@ -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 |
||||
} |
||||
) |
||||
} |
||||
} |
@ -1,90 +1,135 @@ |
||||
import { PluginClient } from '@remixproject/plugin' |
||||
import { createClient } from '@remixproject/plugin-webview' |
||||
import { w3mConnectors, w3mProvider } from '@web3modal/ethereum' |
||||
import { createConfig, configureChains } from 'wagmi' |
||||
import { arbitrum, arbitrumGoerli, mainnet, polygon, polygonMumbai, optimism, optimismGoerli, Chain, goerli, sepolia } from 'viem/chains' |
||||
import { EthereumClient } from '@web3modal/ethereum' |
||||
import EventManager from "events" |
||||
import { PROJECT_ID } from './constant' |
||||
import {PluginClient} from '@remixproject/plugin' |
||||
import {createClient} from '@remixproject/plugin-webview' |
||||
import {w3mConnectors, w3mProvider} from '@web3modal/ethereum' |
||||
import {createConfig, configureChains} from 'wagmi' |
||||
import { |
||||
arbitrum, |
||||
arbitrumGoerli, |
||||
mainnet, |
||||
polygon, |
||||
polygonMumbai, |
||||
optimism, |
||||
optimismGoerli, |
||||
Chain, |
||||
goerli, |
||||
sepolia |
||||
} from 'viem/chains' |
||||
import {EthereumClient} from '@web3modal/ethereum' |
||||
import EventManager from 'events' |
||||
import {PROJECT_ID} from './constant' |
||||
|
||||
export class WalletConnectRemixClient extends PluginClient { |
||||
wagmiConfig |
||||
ethereumClient: EthereumClient |
||||
chains: Chain[] |
||||
currentChain: number |
||||
internalEvents: EventManager |
||||
wagmiConfig |
||||
ethereumClient: EthereumClient |
||||
chains: Chain[] |
||||
currentChain: number |
||||
internalEvents: EventManager |
||||
|
||||
constructor() { |
||||
super() |
||||
createClient(this) |
||||
this.internalEvents = new EventManager() |
||||
this.methods = ["sendAsync", "init", "deactivate"] |
||||
this.onload() |
||||
} |
||||
constructor() { |
||||
super() |
||||
createClient(this) |
||||
this.internalEvents = new EventManager() |
||||
this.methods = ['sendAsync', 'init', 'deactivate'] |
||||
this.onload() |
||||
} |
||||
|
||||
onActivation () { |
||||
this.subscribeToEvents() |
||||
this.call('theme', 'currentTheme').then((theme: any) => { |
||||
this.internalEvents.emit('themeChanged', theme.quality.toLowerCase()) |
||||
}) |
||||
} |
||||
onActivation() { |
||||
this.subscribeToEvents() |
||||
this.call('theme', 'currentTheme').then((theme: any) => { |
||||
this.internalEvents.emit('themeChanged', theme.quality.toLowerCase()) |
||||
}) |
||||
} |
||||
|
||||
init () { |
||||
console.log('initializing walletconnect plugin...') |
||||
} |
||||
init() { |
||||
console.log('initializing walletconnect plugin...') |
||||
} |
||||
|
||||
async initClient () { |
||||
try { |
||||
this.chains = [arbitrum, arbitrumGoerli, mainnet, polygon, polygonMumbai, optimism, optimismGoerli, goerli, sepolia] |
||||
const { publicClient } = configureChains(this.chains, [w3mProvider({ projectId: PROJECT_ID })]) |
||||
async initClient() { |
||||
try { |
||||
this.chains = [ |
||||
mainnet, |
||||
arbitrum, |
||||
arbitrumGoerli, |
||||
polygon, |
||||
polygonMumbai, |
||||
optimism, |
||||
optimismGoerli, |
||||
goerli, |
||||
sepolia |
||||
] |
||||
const {publicClient} = configureChains(this.chains, [ |
||||
w3mProvider({projectId: PROJECT_ID}) |
||||
]) |
||||
|
||||
this.wagmiConfig = createConfig({ |
||||
autoConnect: false, |
||||
connectors: w3mConnectors({ projectId: PROJECT_ID, chains: this.chains }), |
||||
publicClient |
||||
}) |
||||
this.ethereumClient = new EthereumClient(this.wagmiConfig, this.chains) |
||||
} catch (e) { |
||||
return console.error("Could not get a wallet connection", e) |
||||
} |
||||
this.wagmiConfig = createConfig({ |
||||
autoConnect: false, |
||||
connectors: w3mConnectors({projectId: PROJECT_ID, chains: this.chains}), |
||||
publicClient |
||||
}) |
||||
this.ethereumClient = new EthereumClient(this.wagmiConfig, this.chains) |
||||
} catch (e) { |
||||
return console.error('Could not get a wallet connection', e) |
||||
} |
||||
} |
||||
|
||||
subscribeToEvents () { |
||||
this.wagmiConfig.subscribe((event) => { |
||||
if (event.status === 'connected') { |
||||
this.emit('accountsChanged', [event.data.account]) |
||||
if (this.currentChain !== event.data.chain.id) { |
||||
this.currentChain = event.data.chain.id |
||||
this.emit('chainChanged', event.data.chain.id) |
||||
} |
||||
} else if (event.status === 'disconnected') { |
||||
this.emit('accountsChanged', []) |
||||
this.emit('chainChanged', 0) |
||||
this.currentChain = 0 |
||||
} |
||||
}) |
||||
this.on('theme', 'themeChanged', (theme: any) => { |
||||
this.internalEvents.emit('themeChanged', theme.quality) |
||||
}) |
||||
} |
||||
subscribeToEvents() { |
||||
this.wagmiConfig.subscribe((event) => { |
||||
if (event.status === 'connected') { |
||||
this.emit('accountsChanged', [event.data.account]) |
||||
if (this.currentChain !== event.data.chain.id) { |
||||
this.currentChain = event.data.chain.id |
||||
this.emit('chainChanged', event.data.chain.id) |
||||
} |
||||
} else if (event.status === 'disconnected') { |
||||
this.emit('accountsChanged', []) |
||||
this.emit('chainChanged', 0) |
||||
this.currentChain = 0 |
||||
} |
||||
}) |
||||
this.on('theme', 'themeChanged', (theme: any) => { |
||||
this.internalEvents.emit('themeChanged', theme.quality) |
||||
}) |
||||
} |
||||
|
||||
sendAsync (data: { method: string, params: string, id: string }) { |
||||
return new Promise((resolve, reject) => { |
||||
if (this.wagmiConfig) { |
||||
this.wagmiConfig.publicClient.request(data).then((message) => { |
||||
resolve({"jsonrpc": "2.0", "result": message, "id": data.id}) |
||||
}).catch((error) => { |
||||
reject(error) |
||||
}) |
||||
} else { |
||||
console.error(`Cannot make ${data.method} request. Remix client is not connect to walletconnect client`) |
||||
resolve({"jsonrpc": "2.0", "result": [], "id": data.id}) |
||||
} |
||||
async sendAsync(data: {method: string; params: string; id: string}) { |
||||
if (this.wagmiConfig.status === 'connected') { |
||||
if (data.method === 'eth_accounts') { |
||||
return { |
||||
jsonrpc: '2.0', |
||||
result: [this.wagmiConfig.data.account], |
||||
id: data.id |
||||
} |
||||
} else { |
||||
const provider = await this.wagmiConfig.connector.getProvider({ |
||||
chainId: this.wagmiConfig.data.chain.id |
||||
}) |
||||
} |
||||
|
||||
async deactivate(){ |
||||
console.log('deactivating walletconnect plugin...') |
||||
await this.ethereumClient.disconnect() |
||||
if (provider.isMetaMask) { |
||||
return new Promise((resolve) => { |
||||
provider.sendAsync(data, (err, response) => { |
||||
if (err) { |
||||
console.error(err) |
||||
return resolve({jsonrpc: '2.0', result: [], id: data.id}) |
||||
} |
||||
return resolve(response) |
||||
}) |
||||
}) |
||||
} else { |
||||
const message = await provider.request(data) |
||||
|
||||
return {jsonrpc: '2.0', result: message, id: data.id} |
||||
} |
||||
} |
||||
} else { |
||||
console.error( |
||||
`Cannot make ${data.method} request. Remix client is not connected to walletconnect client` |
||||
) |
||||
return {jsonrpc: '2.0', result: [], id: data.id} |
||||
} |
||||
} |
||||
} |
||||
|
||||
async deactivate() { |
||||
console.log('deactivating walletconnect plugin...') |
||||
await this.ethereumClient.disconnect() |
||||
} |
||||
} |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,3 @@ |
||||
{ |
||||
"**/*.{tsx,ts,js}": ["prettier --write","eslint --fix"] |
||||
} |
Loading…
Reference in new issue