Create react UI for circom plugin

pull/3996/head
ioedeveloper 2 years ago
parent ea70c15de3
commit 1cabf35af1
  1. 59
      apps/circuit-compiler/project.json
  2. 6
      apps/circuit-compiler/src/app/actions/dispatch.ts
  3. 14
      apps/circuit-compiler/src/app/actions/index.ts
  4. 56
      apps/circuit-compiler/src/app/app.tsx
  5. 4
      apps/circuit-compiler/src/app/contexts/index.ts
  6. 18
      apps/circuit-compiler/src/app/reducers/index.ts
  7. 37
      apps/circuit-compiler/src/app/services/circomPluginClient.ts
  8. 22
      apps/circuit-compiler/src/app/types/index.ts
  9. 0
      apps/circuit-compiler/src/css/app.css
  10. 10
      apps/circuit-compiler/src/example/simple.circom
  11. 15
      apps/circuit-compiler/src/index.html
  12. 1
      apps/circuit-compiler/src/logo.svg
  13. 8
      apps/circuit-compiler/src/main.tsx
  14. 7
      apps/circuit-compiler/src/polyfills.ts
  15. 17
      apps/circuit-compiler/src/profile.json
  16. 24
      apps/circuit-compiler/tsconfig.app.json
  17. 17
      apps/circuit-compiler/tsconfig.json
  18. 90
      apps/circuit-compiler/webpack.config.js
  19. 2
      apps/remix-ide/project.json
  20. 2
      apps/remix-ide/src/remixAppManager.js
  21. 1
      apps/remix-ide/src/remixEngine.js
  22. 8
      libs/remix-ui/helper/src/lib/helper-components.tsx
  23. 10
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx

@ -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,6 @@
import { Dispatch } from "react"
import { Action } from "../types"
export const dispatchCheckRemixd = (status: boolean) => (dispatch: Dispatch<Action<'SET_REMIXD_CONNECTION_STATUS'>>) => {
dispatch({ type: 'SET_REMIXD_CONNECTION_STATUS', payload: status })
}

@ -0,0 +1,14 @@
import { Dispatch } from 'react'
import { CircomPluginClient } from '../services/circomPluginClient'
const plugin = new CircomPluginClient()
export const initCircomPluginActions = () => async (dispatch: Dispatch<any>) => {
plugin.internalEvents.on('connectionChanged', (connected: boolean) => {
dispatch({ type: 'SET_REMIXD_CONNECTION_STATUS', payload: connected })
})
}
export function activateRemixd () {
plugin.activateRemixDeamon()
}

@ -0,0 +1,56 @@
import React, { useEffect, useReducer } from 'react'
import { RenderIf, RenderIfNot } from '@remix-ui/helper'
import { Alert, Button, Tabs, Tab } from 'react-bootstrap'
import { AppContext } from './contexts'
import { appInitialState, appReducer } from './reducers'
import { activateRemixd, initCircomPluginActions } from './actions'
function App() {
const [appState, dispatch] = useReducer(appReducer, appInitialState)
useEffect(() => {
initCircomPluginActions()(dispatch)
}, [])
const handleConnectRemixd = () => {
activateRemixd()
}
const value = {
appState,
dispatch
}
return (
<AppContext.Provider value={value}>
<div className="App">
<RenderIfNot condition={appState.isRemixdConnected}>
<Alert variant="info" dismissible>
<Alert.Heading>Requirements!</Alert.Heading>
<ol>
<li>Circuit Compiler requires that you have Rust lang installed on your machine.</li>
<li>Remix-IDE is connected to your local file system.</li>
</ol>
<div className="d-flex justify-content-end">
<Button variant='outline-primary' onClick={handleConnectRemixd}>Connect to File System </Button>
</div>
</Alert>
</RenderIfNot>
<RenderIf condition={appState.isRemixdConnected}>
<div className='mx-2 mb-2 d-flex flex-column'>
<Tabs
defaultActiveKey={'compile'}
id="circuitCompilerTabs"
>
<Tab eventKey={'compile'} title="Compiler"></Tab>
<Tab eventKey={'witness'} title="Witness"></Tab>
</Tabs>
</div>
</RenderIf>
</div>
</AppContext.Provider>
)
}
export default App

@ -0,0 +1,4 @@
import { createContext } from 'react'
import { IAppContext } from '../types'
export const AppContext = createContext<IAppContext>({} as IAppContext)

@ -0,0 +1,18 @@
import { Actions, AppState } from "../types"
export const appInitialState: AppState = {
isRemixdConnected: null
}
export const appReducer = (state = appInitialState, action: Actions): AppState => {
switch (action.type) {
case 'SET_REMIXD_CONNECTION_STATUS':
return {
...state,
isRemixdConnected: action.payload
}
default:
throw new Error()
}
}

@ -0,0 +1,37 @@
import { PluginClient } from '@remixproject/plugin'
import { createClient } from '@remixproject/plugin-webview'
import EventManager from 'events'
export class CircomPluginClient extends PluginClient {
private connected: boolean
public internalEvents: EventManager
constructor() {
super()
createClient(this)
this.internalEvents = new EventManager()
this.methods = ["sendAsync", "init", "deactivate"]
this.onload()
}
init (): void {
console.log('initializing circom plugin...')
}
onActivation(): void {
this.subscribeToEvents()
}
activateRemixDeamon (): void {
this.call('manager', 'activatePlugin', 'remixd')
}
subscribeToEvents (): void {
this.on('filePanel', 'setWorkspace', (workspace: { name: string, isLocalhost: boolean }) => {
if (this.connected !== workspace.isLocalhost) {
this.connected = workspace.isLocalhost
this.internalEvents.emit('connectionChanged', this.connected)
}
})
}
}

@ -0,0 +1,22 @@
import { Dispatch } from "react"
export interface IAppContext {
appState: AppState,
dispatch: Dispatch<any>
}
export interface ActionPayloadTypes {
SET_REMIXD_CONNECTION_STATUS: boolean
}
export interface Action <T extends keyof ActionPayloadTypes> {
type: T
payload: ActionPayloadTypes[T]
}
export type Actions = { [A in keyof ActionPayloadTypes]: Action<A> }[keyof ActionPayloadTypes]
export interface AppState {
isRemixdConnected: boolean
}

@ -0,0 +1,10 @@
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 @@
<svg id="Ebene_2" data-name="Ebene 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105 100"><title>remix_logo1</title><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="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>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -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": ["sendAsync", "init"],
"canActivate": ["remixd"],
"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,90 @@
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/
}
return config;
});

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

@ -17,7 +17,7 @@ const requiredModules = [ // services + layout views + system views
// dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd)
const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither'] const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither']
const loadLocalPlugins = ["doc-gen", "doc-viewer", "etherscan", "vyper", 'solhint', 'walletconnect'] const loadLocalPlugins = ["doc-gen", "doc-viewer", "etherscan", "vyper", "solhint", "walletconnect", "circuit-compiler"]
const sensitiveCalls = { const sensitiveCalls = {
'fileManager': ['writeFile', 'copyFile', 'rename', 'copyDir'], 'fileManager': ['writeFile', 'copyFile', 'rename', 'copyDir'],

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

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

@ -514,8 +514,8 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
const compile = () => { const compile = () => {
const currentFile = api.currentFile const currentFile = api.currentFile
if (currentFile.endsWith('.circom')) return compileCircuit()
if (!isSolFileSelected()) return if (!isSolFileSelected()) return
_setCompilerVersionFromPragma(currentFile) _setCompilerVersionFromPragma(currentFile)
let externalCompType let externalCompType
if (hhCompilation) externalCompType = 'hardhat' if (hhCompilation) externalCompType = 'hardhat'
@ -526,8 +526,8 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
const compileAndRun = () => { const compileAndRun = () => {
const currentFile = api.currentFile const currentFile = api.currentFile
if (currentFile.endsWith('.circom')) return compileCircuit()
if (!isSolFileSelected()) return if (!isSolFileSelected()) return
_setCompilerVersionFromPragma(currentFile) _setCompilerVersionFromPragma(currentFile)
let externalCompType let externalCompType
if (hhCompilation) externalCompType = 'hardhat' if (hhCompilation) externalCompType = 'hardhat'
@ -536,6 +536,12 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
compileTabLogic.runCompiler(externalCompType) compileTabLogic.runCompiler(externalCompType)
} }
const compileCircuit = () => {
const currentFile = api.currentFile
console.log('Compiling circuit ' + currentFile)
}
const _updateVersionSelector = (version, customUrl = '') => { const _updateVersionSelector = (version, customUrl = '') => {
// update selectedversion of previous one got filtered out // update selectedversion of previous one got filtered out
let selectedVersion = version let selectedVersion = version

Loading…
Cancel
Save