Merge remote-tracking branch 'origin/master' into startCoding

pull/3654/head
yann300 1 year ago
commit 41ecde7fd7
  1. 4
      apps/circuit-compiler/project.json
  2. 43
      apps/circuit-compiler/src/app/actions/index.ts
  3. 138
      apps/circuit-compiler/src/app/app.tsx
  4. 11
      apps/circuit-compiler/src/app/components/actions.tsx
  5. 51
      apps/circuit-compiler/src/app/components/compileBtn.tsx
  6. 36
      apps/circuit-compiler/src/app/components/configToggler.tsx
  7. 38
      apps/circuit-compiler/src/app/components/configurations.tsx
  8. 81
      apps/circuit-compiler/src/app/components/container.tsx
  9. 60
      apps/circuit-compiler/src/app/components/feedback.tsx
  10. 31
      apps/circuit-compiler/src/app/components/feedbackAlert.tsx
  11. 36
      apps/circuit-compiler/src/app/components/options.tsx
  12. 43
      apps/circuit-compiler/src/app/components/r1csBtn.tsx
  13. 26
      apps/circuit-compiler/src/app/components/versions.tsx
  14. 50
      apps/circuit-compiler/src/app/components/witness.tsx
  15. 36
      apps/circuit-compiler/src/app/components/witnessToggler.tsx
  16. 4
      apps/circuit-compiler/src/app/contexts/index.ts
  17. 77
      apps/circuit-compiler/src/app/reducers/state.ts
  18. 325
      apps/circuit-compiler/src/app/services/circomPluginClient.ts
  19. 87
      apps/circuit-compiler/src/app/types/index.ts
  20. 88
      apps/circuit-compiler/src/css/app.css
  21. 27
      apps/circuit-compiler/src/example/hash.circom
  22. 2
      apps/circuit-compiler/src/example/simple.circom
  23. 8
      apps/circuit-compiler/src/index.html
  24. 8
      apps/circuit-compiler/src/profile.json
  25. 9
      apps/circuit-compiler/src/snarkjs.min.js
  26. 6
      apps/remix-ide-e2e/src/commands/clickInstance.ts
  27. 8
      apps/remix-ide-e2e/src/commands/verifyCallReturnValue.ts
  28. 2
      apps/remix-ide-e2e/src/commands/verifyContracts.ts
  29. 10
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  30. 36
      apps/remix-ide-e2e/src/tests/transactionExecution.test.ts
  31. 22
      apps/remix-ide/src/app/files/fileManager.ts
  32. 10
      apps/remix-ide/src/app/files/fileProvider.js
  33. 2
      apps/remix-ide/src/app/providers/mainnet-vm-fork-provider.tsx
  34. 15
      apps/remix-ide/src/app/tabs/locales/en/circuit.json
  35. 1
      apps/remix-ide/src/app/tabs/locales/en/filePanel.json
  36. 2
      apps/remix-ide/src/app/tabs/locales/en/index.js
  37. 15
      apps/remix-ide/src/app/tabs/locales/es/circuit.json
  38. 15
      apps/remix-ide/src/app/tabs/locales/fr/circuit.json
  39. 16
      apps/remix-ide/src/app/tabs/locales/zh/circuit.json
  40. 2
      apps/remix-ide/src/app/tabs/locales/zh/index.js
  41. BIN
      apps/remix-ide/src/assets/img/circom-icon-bw-800b.webp
  42. BIN
      apps/remix-ide/src/assets/img/circom.webp
  43. 3175
      apps/remix-ide/src/assets/js/parser/antlr.js
  44. 3
      apps/remix-ide/src/remixAppManager.js
  45. 2
      libs/remix-ui/helper/src/lib/remix-ui-helper.ts
  46. 6
      libs/remix-ui/solidity-compile-details/src/lib/solidity-compile-details.tsx
  47. 3
      libs/remix-ui/solidity-compiler/src/index.ts
  48. 6
      libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx
  49. 4
      libs/remix-ui/solidity-compiler/src/lib/types/index.ts
  50. 5
      libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx
  51. 10
      libs/remix-ui/workspace/src/lib/actions/events.ts
  52. 15
      libs/remix-ui/workspace/src/lib/actions/index.ts
  53. 118
      libs/remix-ui/workspace/src/lib/actions/payload.ts
  54. 21
      libs/remix-ui/workspace/src/lib/actions/workspace.ts
  55. 4
      libs/remix-ui/workspace/src/lib/components/file-explorer.tsx
  56. 4
      libs/remix-ui/workspace/src/lib/components/file-render.tsx
  57. 97
      libs/remix-ui/workspace/src/lib/reducers/workspace.ts
  58. 10
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  59. 263
      libs/remix-ui/workspace/src/lib/types/index.ts
  60. 3
      libs/remix-ui/workspace/src/lib/utils/constants.ts
  61. 1
      libs/remix-ws-templates/src/index.ts
  62. 8
      libs/remix-ws-templates/src/templates/ozerc1155/index.ts
  63. 23
      libs/remix-ws-templates/src/templates/ozerc1155/tests/MyToken_mintable_test.sol
  64. 1
      libs/remix-ws-templates/src/templates/ozerc20/index.ts
  65. 6
      libs/remix-ws-templates/src/templates/ozerc20/tests/MyToken_mintable_test.sol
  66. 7
      libs/remix-ws-templates/src/templates/ozerc721/index.ts
  67. 22
      libs/remix-ws-templates/src/templates/ozerc721/tests/MyToken_mintable_test.sol
  68. 9
      libs/remix-ws-templates/src/templates/semaphore/README.txt
  69. 90
      libs/remix-ws-templates/src/templates/semaphore/circuits/semaphore.circom
  70. 11
      libs/remix-ws-templates/src/templates/semaphore/circuits/simple.circom
  71. 40
      libs/remix-ws-templates/src/templates/semaphore/circuits/tree.circom
  72. 18
      libs/remix-ws-templates/src/templates/semaphore/index.ts
  73. 72
      libs/remix-ws-templates/src/templates/semaphore/scripts/run_setup.ts
  74. 102
      libs/remix-ws-templates/src/templates/semaphore/scripts/run_verification.ts
  75. 165
      libs/remix-ws-templates/src/templates/semaphore/templates/groth16_verifier.sol.ejs
  76. 3
      package.json
  77. 0
      pkg/index.js
  78. 253
      yarn.lock

@ -3,7 +3,7 @@
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/circuit-compiler/src",
"projectType": "application",
"implicitDependencies": ["remixd"],
"implicitDependencies": [],
"targets": {
"build": {
"executor": "@nrwl/webpack:webpack",
@ -17,7 +17,7 @@
"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"],
"assets": ["apps/circuit-compiler/src/profile.json", "apps/circuit-compiler/src/snarkjs.min.js"],
"styles": ["apps/circuit-compiler/src/css/app.css"],
"scripts": [],
"webpackConfig": "apps/circuit-compiler/webpack.config.js"

@ -0,0 +1,43 @@
import type { CircomPluginClient } from "../services/circomPluginClient"
import { Actions, AppState } from "../types"
export const compileCircuit = async (plugin: CircomPluginClient, appState: AppState) => {
try {
if (appState.status !== "compiling") {
await plugin.compile(appState.filePath, { version: appState.version, prime: appState.primeValue })
} else {
console.log('Exisiting circuit compilation in progress')
}
} catch (e) {
plugin.internalEvents.emit('circuit_compiling_errored', e)
console.error(e)
}
}
export const generateR1cs = async (plugin: CircomPluginClient, appState: AppState) => {
try {
if (appState.status !== "generating") {
await plugin.generateR1cs(appState.filePath, { version: appState.version, prime: appState.primeValue })
} else {
console.log('Exisiting r1cs generation in progress')
}
} catch (e) {
plugin.internalEvents.emit('circuit_generating_r1cs_errored', e)
console.error('Generating R1CS failed: ', e)
}
}
export const computeWitness = async (plugin: CircomPluginClient, status: string, witnessValues: Record<string, string>) => {
try {
if (status !== "computing") {
const input = JSON.stringify(witnessValues)
await plugin.computeWitness(input)
} else {
console.log('Exisiting witness computation in progress')
}
} catch (e) {
plugin.internalEvents.emit('circuit_computing_witness_errored', e)
console.error('Computing witness failed: ', e)
}
}

@ -1,17 +1,143 @@
import React, { useEffect } from 'react'
import React, {useEffect, useReducer, useState} from 'react'
import {RenderIf} from '@remix-ui/helper'
import {IntlProvider} from 'react-intl'
import { CircomPluginClient } from './services/circomPluginClient'
import { Container } from './components/container'
import {CircuitAppContext} from './contexts'
import {appInitialState, appReducer} from './reducers/state'
import {CircomPluginClient} from './services/circomPluginClient'
import { compileCircuit } from './actions'
const plugin = new CircomPluginClient()
function App() {
const [appState, dispatch] = useReducer(appReducer, appInitialState)
const [locale, setLocale] = useState<{code: string; messages: any}>({
code: 'en',
messages: null
})
const [isContentChanged, setIsContentChanged] = useState<boolean>(false)
const [isPluginActivated, setIsPluginActivated] = useState<boolean>(false)
useEffect(() => {
new CircomPluginClient()
plugin.internalEvents.on('circom_activated', () => {
// @ts-ignore
plugin.on('locale', 'localeChanged', (locale: any) => {
setLocale(locale)
})
plugin.on('fileManager', 'currentFileChanged', (filePath) => {
if (filePath.endsWith('.circom')) {
dispatch({ type: 'SET_FILE_PATH', payload: filePath })
plugin.parse(filePath)
} else {
dispatch({ type: 'SET_FILE_PATH', payload: '' })
}
})
// @ts-ignore
plugin.on('editor', 'contentChanged', async (path: string, content: string) => {
setIsContentChanged(true)
if (path.endsWith('.circom')) {
plugin.parse(path, content)
}
})
setIsPluginActivated(true)
})
// compiling events
plugin.internalEvents.on('circuit_compiling_start', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'compiling' }))
plugin.internalEvents.on('circuit_compiling_done', (signalInputs: string[]) => {
signalInputs = (signalInputs || []).filter(input => input)
dispatch({ type: 'SET_SIGNAL_INPUTS', payload: signalInputs })
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' })
})
plugin.internalEvents.on('circuit_compiling_errored', compilerErrored)
// r1cs events
plugin.internalEvents.on('circuit_generating_r1cs_start', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'generating' }))
plugin.internalEvents.on('circuit_generating_r1cs_done', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' }))
plugin.internalEvents.on('circuit_generating_r1cs_errored', compilerErrored)
// witness events
plugin.internalEvents.on('circuit_computing_witness_start', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'computing' }))
plugin.internalEvents.on('circuit_computing_witness_done', () => {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' })
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: null })
})
plugin.internalEvents.on('circuit_computing_witness_errored', compilerErrored)
// parsing events
plugin.internalEvents.on('circuit_parsing_done', (_, filePathToId) => {
dispatch({ type: 'SET_FILE_PATH_TO_ID', payload: filePathToId })
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: null })
})
plugin.internalEvents.on('circuit_parsing_errored', (report) => {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' })
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: report })
})
plugin.internalEvents.on('circuit_parsing_warning', (report) => {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'warning' })
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: report })
})
}, [])
useEffect(() => {
if (isContentChanged) {
(async () => {
if (appState.autoCompile) await compileCircuit(plugin, appState)
})()
setIsContentChanged(false)
}
}, [appState.autoCompile, isContentChanged])
useEffect(() => {
if (isPluginActivated) {
setCurrentLocale()
}
}, [isPluginActivated])
useEffect(() => {
if (appState.filePath) {
(async () => {
if (appState.autoCompile) await compileCircuit(plugin, appState)
})()
}
}, [appState.filePath])
const setCurrentLocale = async () => {
// @ts-ignore
const currentLocale = await plugin.call('locale', 'currentLocale')
setLocale(currentLocale)
}
const compilerErrored = (err: ErrorEvent) => {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' })
try {
const report = JSON.parse(err.message)
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: report })
} catch (e) {
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: err.message })
}
}
const value = {
appState,
dispatch,
plugin
}
return (
<div className="App">
<div className="circuit_compiler_app">
<RenderIf condition={locale.messages}>
<IntlProvider locale={locale.code} messages={locale.messages}>
<CircuitAppContext.Provider value={value}>
<Container />
</CircuitAppContext.Provider>
</IntlProvider>
</RenderIf>
</div>
)
}
export default App
export default App

@ -0,0 +1,11 @@
import { CompileBtn } from "./compileBtn";
import { R1CSBtn } from "./r1csBtn";
export function CircuitActions () {
return (
<div className="pb-3">
<CompileBtn />
<R1CSBtn />
</div>
)
}

@ -0,0 +1,51 @@
import { CustomTooltip, RenderIf, RenderIfNot, extractNameFromKey } from "@remix-ui/helper";
import { useContext } from "react";
import { CircuitAppContext } from "../contexts";
import { FormattedMessage } from "react-intl";
import { compileCircuit } from "../actions";
export function CompileBtn () {
const { plugin, appState } = useContext(CircuitAppContext)
return (
<button
className="btn btn-primary btn-block d-block w-100 text-break mb-1 mt-3"
onClick={() => { compileCircuit(plugin, appState) }}
disabled={(appState.filePath === "") || (appState.status === "compiling") || (appState.status === "generating")}
>
<CustomTooltip
placement="auto"
tooltipId="overlay-tooltip-compile"
tooltipText={
<div className="text-left">
<div>
<b>Ctrl+S</b> to compile {appState.filePath}
</div>
</div>
}
>
<div className="d-flex align-items-center justify-content-center">
<RenderIf condition={appState.status === 'compiling'}>
<i className="fas fa-sync fa-spin mr-2" aria-hidden="true"></i>
</RenderIf>
<RenderIfNot condition={appState.status === 'compiling'}>
<i className="fas fa-sync mr-2" aria-hidden="true"></i>
</RenderIfNot>
<div className="text-truncate overflow-hidden text-nowrap">
<span>
<FormattedMessage id="circuit.compile" />
</span>
<span className="ml-1 text-nowrap">
<RenderIf condition={appState.filePath === ""}>
<FormattedMessage id="circuit.noFileSelected" />
</RenderIf>
<RenderIfNot condition={appState.filePath === ""}>
<>{extractNameFromKey(appState.filePath)}</>
</RenderIfNot>
</span>
</div>
</div>
</CustomTooltip>
</button>
)
}

@ -0,0 +1,36 @@
import { useState } from "react"
import { FormattedMessage } from "react-intl"
import { RenderIf, RenderIfNot } from "@remix-ui/helper"
export function ConfigToggler ({ children }: { children: JSX.Element }) {
const [toggleExpander, setToggleExpander] = useState<boolean>(false)
const toggleConfigurations = () => {
setToggleExpander(!toggleExpander)
}
return (
<div>
<div className="d-flex circuit_config_section justify-content-between" onClick={toggleConfigurations}>
<div className="d-flex">
<label className="mt-1 circuit_config_section">
<FormattedMessage id="circuit.advancedConfigurations" />
</label>
</div>
<div>
<span data-id="scConfigExpander" onClick={toggleConfigurations}>
<RenderIf condition={toggleExpander}>
<i className="fas fa-angle-down" aria-hidden="true"></i>
</RenderIf>
<RenderIfNot condition={toggleExpander}>
<i className="fas fa-angle-right" aria-hidden="true"></i>
</RenderIfNot>
</span>
</div>
</div>
<RenderIf condition={toggleExpander}>
{ children }
</RenderIf>
</div>
)
}

@ -0,0 +1,38 @@
import { CustomTooltip } from "@remix-ui/helper"
import { FormattedMessage } from "react-intl"
import { ConfigurationsProps, PrimeValue } from "../types"
export function Configurations ({primeValue, setPrimeValue}: ConfigurationsProps) {
return (
<div className="pb-2 border-bottom flex-column">
<div className="flex-column d-flex">
<div className="mb-2 ml-0">
<label className="circuit_inner_label form-check-label" htmlFor="circuitPrimeSelector">
<FormattedMessage id="circuit.prime" />
</label>
<CustomTooltip
placement={"auto"}
tooltipId="circuitPrimeLabelTooltip"
tooltipClasses="text-nowrap"
tooltipText={<span>{'To choose the prime number to use to generate the circuit. Receives the name of the curve (bn128, bls12381, goldilocks) [default: bn128]'}</span>}
>
<div>
<select
onChange={(e) => setPrimeValue(e.target.value as PrimeValue)}
value={primeValue}
className="custom-select"
style={{
pointerEvents: 'auto'
}}
>
<option value="bn128">bn128</option>
<option value="bls12381">bls12381</option>
<option value="goldilocks">goldilocks</option>
</select>
</div>
</CustomTooltip>
</div>
</div>
</div>
)
}

@ -0,0 +1,81 @@
import { useContext } from 'react'
import { CustomTooltip, RenderIf } from '@remix-ui/helper'
import {FormattedMessage} from 'react-intl'
import { CircuitAppContext } from '../contexts'
import { CompileOptions } from './options'
import { VersionList } from './versions'
import { ConfigToggler } from './configToggler'
import { Configurations } from './configurations'
import { CircuitActions } from './actions'
import { WitnessToggler } from './witnessToggler'
import { WitnessSection } from './witness'
import { CompilerFeedback } from './feedback'
import { PrimeValue } from '../types'
export function Container () {
const circuitApp = useContext(CircuitAppContext)
const showCompilerLicense = (message = 'License not available') => {
// @ts-ignore
circuitApp.plugin.call('notification', 'modal', { id: 'modal_circuit_compiler_license', title: 'Compiler License', message })
}
const handleVersionSelect = (version: string) => {
circuitApp.dispatch({ type: 'SET_COMPILER_VERSION', payload: version })
}
const handleOpenErrorLocation = async (location: string, startRange: string) => {
if (location) {
const fullPathLocation = await circuitApp.plugin.resolveReportPath(location)
await circuitApp.plugin.call('fileManager', 'open', fullPathLocation)
// @ts-ignore
const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange)
// @ts-ignore
await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column)
}
}
const handlePrimeChange = (value: string) => {
circuitApp.dispatch({ type: 'SET_PRIME_VALUE', payload: value as PrimeValue })
}
const handleCircuitAutoCompile = (value: boolean) => {
circuitApp.dispatch({ type: 'SET_AUTO_COMPILE', payload: value })
}
const handleCircuitHideWarnings = (value: boolean) => {
circuitApp.dispatch({ type: 'SET_HIDE_WARNINGS', payload: value })
}
return (
<section>
<article>
<div className="pt-0 circuit_section">
<div className="mb-1">
<label className="circuit_label form-check-label" htmlFor="versionSelector">
<FormattedMessage id="circuit.compiler" />
</label>
<CustomTooltip placement="top" tooltipId="showCompilerTooltip" tooltipClasses="text-nowrap" tooltipText={'See compiler license'}>
<span className="fa fa-file-text-o border-0 p-0 ml-2" onClick={() => showCompilerLicense()}></span>
</CustomTooltip>
<VersionList setVersion={handleVersionSelect} versionList={circuitApp.appState.versionList} currentVersion={circuitApp.appState.version} />
<CompileOptions setCircuitAutoCompile={handleCircuitAutoCompile} setCircuitHideWarnings={handleCircuitHideWarnings} autoCompile={circuitApp.appState.autoCompile} hideWarnings={circuitApp.appState.hideWarnings} />
<ConfigToggler>
<Configurations setPrimeValue={handlePrimeChange} primeValue={circuitApp.appState.primeValue} />
</ConfigToggler>
<CircuitActions />
<RenderIf condition={circuitApp.appState.signalInputs.length > 0}>
<WitnessToggler>
<WitnessSection plugin={circuitApp.plugin} signalInputs={circuitApp.appState.signalInputs} status={circuitApp.appState.status} />
</WitnessToggler>
</RenderIf>
<RenderIf condition={circuitApp.appState.status !== 'compiling' && circuitApp.appState.status !== 'computing' && circuitApp.appState.status !== 'generating'}>
<CompilerFeedback feedback={circuitApp.appState.feedback} filePathToId={circuitApp.appState.filePathToId} openErrorLocation={handleOpenErrorLocation} hideWarnings={circuitApp.appState.hideWarnings} />
</RenderIf>
</div>
</div>
</article>
</section>
)
}

@ -0,0 +1,60 @@
import { useState } from 'react'
import { CompilerFeedbackProps, CompilerReport } from '../types'
import { RenderIf } from '@remix-ui/helper'
import {CopyToClipboard} from '@remix-ui/clipboard'
import { FeedbackAlert } from './feedbackAlert'
export function CompilerFeedback ({ feedback, filePathToId, hideWarnings, openErrorLocation }: CompilerFeedbackProps) {
const [ showException, setShowException ] = useState<boolean>(true)
const handleCloseException = () => {
setShowException(false)
}
const handleOpenError = (report: CompilerReport) => {
if (report.labels.length > 0) {
openErrorLocation(filePathToId[report.labels[0].file_id], report.labels[0].range.start)
}
}
return (
<div>
<div className="circuit_errors_box py-4">
<RenderIf condition={ (typeof feedback === "string") && showException }>
<div className="circuit_feedback error alert alert-danger">
<span> { feedback } </span>
<div className="close" data-id="renderer" onClick={handleCloseException}>
<i className="fas fa-times"></i>
</div>
<div className="d-flex pt-1 flex-row-reverse">
<span className="ml-3 pt-1 py-1" >
<CopyToClipboard content={feedback} className="p-0 m-0 far fa-copy error" direction={'top'} />
</span>
</div>
</div>
</RenderIf>
<RenderIf condition={ Array.isArray(feedback) }>
<>
{
Array.isArray(feedback) && feedback.map((response, index) => (
<div key={index} onClick={() => handleOpenError(response)}>
<RenderIf condition={response.type === 'Error'}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-danger`}>
<FeedbackAlert message={response.message} location={ response.labels[0] ? response.labels[0].message + ` ${filePathToId[response.labels[0].file_id]}:${response.labels[0].range.start}:${response.labels[0].range.end}` : null} />
</div>
</RenderIf>
<RenderIf condition={(response.type === 'Warning') && !hideWarnings}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-warning`}>
<FeedbackAlert message={response.message} location={null} />
</div>
</RenderIf>
</div>
)
)
}
</>
</RenderIf>
</div>
</div>
)
}

@ -0,0 +1,31 @@
import { useState } from 'react'
import { FeedbackAlertProps } from '../types'
import { RenderIf } from '@remix-ui/helper'
import {CopyToClipboard} from '@remix-ui/clipboard'
export function FeedbackAlert ({ message, location }: FeedbackAlertProps) {
const [ showAlert, setShowAlert] = useState<boolean>(true)
const handleCloseAlert = () => {
setShowAlert(false)
}
return (
<RenderIf condition={showAlert}>
<>
<span> { message } </span>
<RenderIf condition={location !== null}>
<span> { location }</span>
</RenderIf>
<div className="close" data-id="renderer" onClick={handleCloseAlert}>
<i className="fas fa-times"></i>
</div>
<div className="d-flex pt-1 flex-row-reverse">
<span className="ml-3 pt-1 py-1" >
<CopyToClipboard content={message} className="p-0 m-0 far fa-copy error" direction={'top'} />
</span>
</div>
</>
</RenderIf>
)
}

@ -0,0 +1,36 @@
import {FormattedMessage} from 'react-intl'
import { CompileOptionsProps } from '../types'
export function CompileOptions ({autoCompile, hideWarnings, setCircuitAutoCompile, setCircuitHideWarnings}: CompileOptionsProps) {
return (
<div className='pb-2'>
<div className="mt-2 custom-control custom-checkbox">
<input
className="custom-control-input"
type="checkbox"
onChange={(e) => setCircuitAutoCompile(e.target.checked)}
title="Auto compile"
checked={autoCompile}
id="autoCompileCircuit"
/>
<label className="form-check-label custom-control-label" htmlFor="autoCompileCircuit">
<FormattedMessage id="circuit.autoCompile" />
</label>
</div>
<div className="mt-1 mb-2 circuit_warnings_box custom-control custom-checkbox">
<input
className="custom-control-input"
onChange={(e) => setCircuitHideWarnings(e.target.checked)}
id="hideCircuitWarnings"
type="checkbox"
title="Hide warnings"
checked={hideWarnings}
/>
<label className="form-check-label custom-control-label" htmlFor="hideCircuitWarnings">
<FormattedMessage id="solidity.hideWarnings" />
</label>
</div>
</div>
)
}

@ -0,0 +1,43 @@
import { CustomTooltip, RenderIf, RenderIfNot } from "@remix-ui/helper";
import { useContext } from "react";
import { CircuitAppContext } from "../contexts";
import { FormattedMessage } from "react-intl";
import { generateR1cs } from "../actions";
export function R1CSBtn () {
const { plugin, appState } = useContext(CircuitAppContext)
return (
<button
className="btn btn-secondary btn-block d-block w-100 text-break mb-1 mt-2"
onClick={() => { generateR1cs(plugin, appState) }}
disabled={(appState.filePath === "") || (appState.status === "compiling") || (appState.status === "generating") || (appState.status === "computing")}
>
<CustomTooltip
placement="auto"
tooltipId="overlay-tooltip-compile"
tooltipText={
<div className="text-left">
<div>
Outputs the constraints in r1cs format
</div>
</div>
}
>
<div className="d-flex align-items-center justify-content-center">
<RenderIf condition={appState.status === 'generating'}>
<i className="fas fa-sync fa-spin mr-2" aria-hidden="true"></i>
</RenderIf>
<RenderIfNot condition={appState.status === 'generating'}>
<i className="fas fa-sync mr-2" aria-hidden="true"></i>
</RenderIfNot>
<div className="text-truncate overflow-hidden text-nowrap">
<span>
<FormattedMessage id="circuit.generateR1cs" />
</span>
</div>
</div>
</CustomTooltip>
</button>
)
}

@ -0,0 +1,26 @@
import { RenderIf } from "@remix-ui/helper";
import { AppState } from "../types";
export function VersionList ({ currentVersion, versionList, setVersion }: { versionList: AppState['versionList'], currentVersion: string, setVersion: (version: string) => void }) {
const versionListKeys = Object.keys(versionList)
return (
<select
value={currentVersion}
onChange={(e) => setVersion(e.target.value)}
className="custom-select"
>
<RenderIf condition={versionListKeys.length > 0}>
<>
{
versionListKeys.map((version, index) => (
<option value={version} key={index}>
{ versionList[version].name }
</option>
))
}
</>
</RenderIf>
</select>
)
}

@ -0,0 +1,50 @@
import { RenderIf, RenderIfNot } from "@remix-ui/helper";
import { FormattedMessage } from "react-intl";
import { CompilerStatus } from "../types";
import { computeWitness } from "../actions";
import { useState } from "react";
import type { CircomPluginClient } from "../services/circomPluginClient";
export function WitnessSection ({ plugin, signalInputs, status }: {plugin: CircomPluginClient, signalInputs: string[], status: CompilerStatus}) {
const [witnessValues, setWitnessValues] = useState<Record<string, string>>({})
const handleSignalInput = (e: any) => {
setWitnessValues({
...witnessValues,
[e.target.name]: e.target.value
})
}
return (
<div className="pb-2 border-bottom flex-column">
<div className="flex-column d-flex">
<RenderIf condition={signalInputs.length > 0}>
<>
{
signalInputs.map((input, index) => (
<div className="mb-2 ml-0" key={index}>
<label className="circuit_inner_label form-check-label" htmlFor="circuitPrimeSelector">
<FormattedMessage id="circuit.signalInput" /> { input }
</label>
<input className="form-control m-0 txinput" placeholder={input} name={input} onChange={handleSignalInput} />
</div>
))
}
<button
className="btn btn-sm btn-secondary"
onClick={() => { computeWitness(plugin, status, witnessValues) }}
disabled={(status === "compiling") || (status === "generating") || (status === "computing")}>
<RenderIf condition={status === 'computing'}>
<i className="fas fa-sync fa-spin mr-2" aria-hidden="true"></i>
</RenderIf>
<RenderIfNot condition={status === 'computing'}>
<i className="fas fa-sync mr-2" aria-hidden="true"></i>
</RenderIfNot>
<FormattedMessage id="circuit.compute" />
</button>
</>
</RenderIf>
</div>
</div>
)
}

@ -0,0 +1,36 @@
import { useState } from "react"
import { FormattedMessage } from "react-intl"
import { RenderIf, RenderIfNot } from "@remix-ui/helper"
export function WitnessToggler ({ children }: { children: JSX.Element }) {
const [toggleExpander, setToggleExpander] = useState<boolean>(false)
const toggleConfigurations = () => {
setToggleExpander(!toggleExpander)
}
return (
<div>
<div className="d-flex circuit_config_section justify-content-between" onClick={toggleConfigurations}>
<div className="d-flex">
<label className="mt-1 circuit_config_section">
<FormattedMessage id="circuit.computeWitness" />
</label>
</div>
<div>
<span data-id="scConfigExpander" onClick={toggleConfigurations}>
<RenderIf condition={toggleExpander}>
<i className="fas fa-angle-down" aria-hidden="true"></i>
</RenderIf>
<RenderIfNot condition={toggleExpander}>
<i className="fas fa-angle-right" aria-hidden="true"></i>
</RenderIfNot>
</span>
</div>
</div>
<RenderIf condition={toggleExpander}>
{ children }
</RenderIf>
</div>
)
}

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

@ -0,0 +1,77 @@
import {Actions, AppState} from '../types'
import { compiler_list } from 'circom_wasm'
export const appInitialState: AppState = {
version: compiler_list.latest,
versionList: compiler_list.wasm_builds,
filePath: "",
filePathToId: {},
status: "idle",
primeValue: "bn128",
autoCompile: false,
hideWarnings: false,
signalInputs: [],
feedback: null
}
export const appReducer = (state = appInitialState, action: Actions): AppState => {
switch (action.type) {
case 'SET_COMPILER_VERSION':
return {
...state,
version: action.payload
}
case 'SET_FILE_PATH':
return {
...state,
filePath: action.payload
}
case 'SET_COMPILER_STATUS':
return {
...state,
status: action.payload
}
case 'SET_PRIME_VALUE':
return {
...state,
primeValue: action.payload
}
case 'SET_AUTO_COMPILE':
return {
...state,
autoCompile: action.payload
}
case 'SET_HIDE_WARNINGS':
return {
...state,
hideWarnings: action.payload
}
case 'SET_SIGNAL_INPUTS':
return {
...state,
signalInputs: action.payload
}
case 'SET_COMPILER_FEEDBACK':
return {
...state,
feedback: action.payload
}
case 'SET_FILE_PATH_TO_ID':
return {
...state,
filePathToId: action.payload
}
default:
throw new Error()
}
}

@ -1,17 +1,26 @@
import {PluginClient} from '@remixproject/plugin'
import {createClient} from '@remixproject/plugin-webview'
import { PluginClient } from '@remixproject/plugin'
import { createClient } from '@remixproject/plugin-webview'
import EventManager from 'events'
import pathModule from 'path'
import {parse} from 'circom_wasm'
import { parse, compile, generate_witness, generate_r1cs, compiler_list } from 'circom_wasm'
import { extractNameFromKey, extractParentFromKey } from '@remix-ui/helper'
import { CompilationConfig, CompilerReport } from '../types'
export class CircomPluginClient extends PluginClient {
public internalEvents: EventManager
private _compilationConfig: CompilationConfig = {
version: "2.1.5",
prime: "bn128"
}
private lastCompiledCircuitPath: string = ''
private lastParsedFiles: Record<string, string> = {}
private lastCompiledFile: string = ''
constructor() {
super()
this.methods = ['init', 'parse', 'compile', 'generateR1cs']
createClient(this)
this.internalEvents = new EventManager()
this.methods = ['init', 'parse']
this.onload()
}
@ -20,24 +29,23 @@ export class CircomPluginClient extends PluginClient {
}
onActivation(): void {
// @ts-ignore
this.on('editor', 'contentChanged', (path: string, fileContent) => {
if (path.endsWith('.circom')) {
this.parse(path, fileContent)
}
})
this.internalEvents.emit('circom_activated')
}
async parse(path: string, fileContent: string): Promise<void> {
let buildFiles = {
[path]: fileContent
async parse(path: string, fileContent?: string): Promise<CompilerReport[]> {
if (!fileContent) {
// @ts-ignore
fileContent = await this.call('fileManager', 'readFile', path)
}
buildFiles = await this.resolveDependencies(path, fileContent, buildFiles)
const parsedOutput = parse(path, buildFiles)
this.lastParsedFiles = {
[path]: fileContent,
}
this.lastParsedFiles = await this.resolveDependencies(path, fileContent, this.lastParsedFiles)
const parsedOutput = parse(path, this.lastParsedFiles)
try {
const result = JSON.parse(parsedOutput)
const result: CompilerReport[] = JSON.parse(parsedOutput.report())
const mapReportFilePathToId = {}
if (result.length === 0) {
// @ts-ignore
@ -47,23 +55,24 @@ export class CircomPluginClient extends PluginClient {
for (const report of result) {
for (const label in report.labels) {
if (report.labels[label].file_id === '0') {
const file_id = report.labels[label].file_id
mapReportFilePathToId[file_id] = parsedOutput.get_report_name(parseInt(file_id))
if (file_id === '0') {
// @ts-ignore
const startPosition: {lineNumber: number; column: number} =
await this.call(
'editor',
// @ts-ignore
'getPositionAt',
report.labels[label].range.start
)
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
)
const endPosition: { lineNumber: number; column: number } = await this.call(
'editor',
// @ts-ignore
'getPositionAt',
report.labels[label].range.end
)
markers.push({
message: report.message,
@ -71,14 +80,14 @@ export class CircomPluginClient extends PluginClient {
position: {
start: {
line: startPosition.lineNumber,
column: startPosition.column
column: startPosition.column,
},
end: {
line: endPosition.lineNumber,
column: endPosition.column
}
column: endPosition.column,
},
},
file: path
file: path,
})
}
}
@ -92,22 +101,117 @@ export class CircomPluginClient extends PluginClient {
await this.call('editor', 'clearErrorMarkers', [path])
}
}
this.internalEvents.emit('circuit_parsing_done', result, mapReportFilePathToId)
return result
} catch (e) {
console.log(e)
throw new Error(e)
}
}
async compile(path: string, compilationConfig?: CompilationConfig): Promise<void> {
this.internalEvents.emit('circuit_compiling_start')
const parseErrors = await this.parse(path)
if (parseErrors && (parseErrors.length > 0)) {
if (parseErrors[0].type === 'Error') {
this.internalEvents.emit('circuit_parsing_errored', parseErrors)
return
} else if (parseErrors[0].type === 'Warning') {
this.internalEvents.emit('circuit_parsing_warning', parseErrors)
}
}
if (compilationConfig) {
const { prime, version } = compilationConfig
if ((prime !== "bn128") && (prime !== "bls12381") && (prime !== "goldilocks")) throw new Error('Invalid prime value')
if (!compiler_list.versions.includes(version)) throw new Error("Unsupported compiler version")
this._compilationConfig.prime = prime
this._compilationConfig.version = version
}
const circuitApi = compile(path, this.lastParsedFiles, { prime: this._compilationConfig.prime })
const circuitProgram = circuitApi.program()
if (circuitProgram.length < 1) {
const circuitErrors = circuitApi.report()
throw new Error(circuitErrors)
} else {
this.lastCompiledFile = path
const fileName = extractNameFromKey(path)
this.lastCompiledCircuitPath = extractParentFromKey(path) + "/.bin/" + fileName.replace('circom', 'wasm')
// @ts-ignore
await this.call('fileManager', 'writeFile', this.lastCompiledCircuitPath, circuitProgram, { encoding: null })
const fileContent = this.lastParsedFiles[path]
const searchComponentName = fileContent.match(/component\s+main\s*(?:{[^{}]*})?\s*=\s*([A-Za-z_]\w*)\s*\(.*\)/)
if (searchComponentName) {
const componentName = searchComponentName[1]
const signals = circuitApi.input_signals(componentName)
this.internalEvents.emit('circuit_compiling_done', signals)
} else {
this.internalEvents.emit('circuit_compiling_done', [])
}
}
}
async generateR1cs (path: string, compilationConfig?: CompilationConfig): Promise<void> {
this.internalEvents.emit('circuit_generating_r1cs_start')
const parseErrors = await this.parse(path)
if (parseErrors && (parseErrors.length > 0)) {
if (parseErrors[0].type === 'Error') {
this.internalEvents.emit('circuit_parsing_errored', parseErrors)
return
} else if (parseErrors[0].type === 'Warning') {
this.internalEvents.emit('circuit_parsing_warning', parseErrors)
}
}
if (compilationConfig) {
const { prime, version } = compilationConfig
if ((prime !== "bn128") && (prime !== "bls12381") && (prime !== "goldilocks")) throw new Error('Invalid prime value')
if (!compiler_list.versions.includes(version)) throw new Error("Unsupported compiler version")
this._compilationConfig.prime = prime
this._compilationConfig.version = version
}
const r1csApi = generate_r1cs(path, this.lastParsedFiles, { prime: this._compilationConfig.prime })
const r1csProgram = r1csApi.program()
if (r1csProgram.length < 1) {
const r1csErrors = r1csApi.report()
throw new Error(r1csErrors)
} else {
this.internalEvents.emit('circuit_generating_r1cs_done')
const fileName = extractNameFromKey(path)
const writePath = extractParentFromKey(path) + "/.bin/" + fileName.replace('circom', 'r1cs')
// @ts-ignore
await this.call('fileManager', 'writeFile', writePath, r1csProgram, true)
}
}
async computeWitness (input: string): Promise<void> {
this.internalEvents.emit('circuit_computing_witness_start')
const wasmPath = this.lastCompiledCircuitPath
if (!wasmPath) throw new Error('No wasm file found')
// @ts-ignore
const buffer: any = await this.call('fileManager', 'readFile', wasmPath, { encoding: null })
const dataRead = new Uint8Array(buffer)
const witness = await generate_witness(dataRead, input)
// @ts-ignore
await this.call('fileManager', 'writeFile', wasmPath.replace('.wasm', '.wtn'), witness, true)
this.internalEvents.emit('circuit_computing_witness_done')
}
async resolveDependencies(
filePath: string,
fileContent: string,
output = {},
depPath: string = '',
blackPath: string[] = []
): Promise<Record<string, string>> {
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, '')
)
const includes = (fileContent.match(/include ['"].*['"]/g) || []).map((include) => include.replace(/include ['"]/g, '').replace(/['"]/g, ''))
await Promise.all(
includes.map(async (include) => {
@ -123,12 +227,8 @@ export class CircomPluginClient extends PluginClient {
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)
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
@ -138,81 +238,40 @@ export class CircomPluginClient extends PluginClient {
if (relativePathExists) {
// fetch file content if include import exists as a relative path
dependencyContent = await this.call(
'fileManager',
'readFile',
relativePath
)
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
)
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 (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
)
}
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 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
)
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, '')
)
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
)
await this.resolveDependencies(filePath, dependencyContent, output, path, blackPath)
output[include] = dependencyContent
} else {
output[include] = dependencyContent
@ -221,4 +280,40 @@ export class CircomPluginClient extends PluginClient {
)
return output
}
async resolveReportPath (path: string): Promise<string> {
// @ts-ignore
const pathExists = await this.call('fileManager', 'exists', path)
if (pathExists) return 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(this.lastCompiledFile.slice(0, this.lastCompiledFile.lastIndexOf('/')), path)
if (relativePath.indexOf('/') === 0) relativePath = relativePath.slice(1)
// @ts-ignore
const relativePathExists = await this.call('fileManager', 'exists', relativePath)
if (relativePathExists) return relativePath
else {
if (path.startsWith('circomlib')) {
// try to resolve include import from github if it is a circomlib dependency
const splitInclude = path.split('/')
const version = splitInclude[1].match(/v[0-9]+.[0-9]+.[0-9]+/g)
if (version && version[0]) {
path = `/.deps/https/raw.githubusercontent.com/iden3/circomlib/${version[0]}/circuits/${splitInclude.slice(2).join('/')}`
} else {
path = `/.deps/https/raw.githubusercontent.com/iden3/circomlib/master/circuits/${splitInclude.slice(1).join('/')}`
}
// @ts-ignore
const exists = await this.call('fileManager', 'exists', path)
if (exists) return path
else throw new Error(`Report path ${path} do no exist in the Remix FileSystem`)
} else {
throw new Error(`Report path ${path} do no exist in the Remix FileSystem`)
}
}
}
}
}

@ -0,0 +1,87 @@
import { compiler_list } from 'circom_wasm'
import {Dispatch} from 'react'
import { CircomPluginClient } from '../services/circomPluginClient'
export type CompilerStatus = "compiling" | "generating" | "computing" | "idle" | "errored" | "warning"
export interface ICircuitAppContext {
appState: AppState
dispatch: Dispatch<Actions>,
plugin: CircomPluginClient
}
export interface ActionPayloadTypes {
SET_COMPILER_VERSION: string,
SET_FILE_PATH: string,
SET_COMPILER_STATUS: CompilerStatus,
SET_PRIME_VALUE: PrimeValue,
SET_AUTO_COMPILE: boolean,
SET_HIDE_WARNINGS: boolean,
SET_SIGNAL_INPUTS: string[],
SET_COMPILER_FEEDBACK: string | CompilerReport[]
SET_FILE_PATH_TO_ID: Record<number, string>
}
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 {
version: string,
versionList: typeof compiler_list.wasm_builds,
filePath: string,
filePathToId: Record<string, string>,
status: CompilerStatus,
primeValue: PrimeValue,
autoCompile: boolean,
hideWarnings: boolean,
signalInputs: string[],
feedback: string | CompilerReport[]
}
export type CompilationConfig = {
prime: PrimeValue,
version: string
}
export type PrimeValue = "bn128" | "bls12381" | "goldilocks"
export type CompilerFeedbackProps = {
feedback: string | CompilerReport[],
filePathToId: Record<string, string>,
openErrorLocation: (location: string, startRange: string) => void,
hideWarnings: boolean
}
export type CompilerReport = {
type: "Error" | "Bug" | "Help" | "Note" | "Warning" | "Unknown",
message: string,
labels: {
style: "Primary" | "Secondary" | "Unknown",
file_id: string,
range: {
start: string,
end: string
},
message: string
}[],
notes: string[]
}
export type FeedbackAlertProps = {
message: string,
location: string
}
export type ConfigurationsProps = {
setPrimeValue: (prime: PrimeValue) => void,
primeValue: PrimeValue
}
export type CompileOptionsProps = {
setCircuitAutoCompile: (value: boolean) => void,
setCircuitHideWarnings: (value: boolean) => void,
autoCompile: boolean,
hideWarnings: boolean
}

@ -0,0 +1,88 @@
body {
font-size : .8rem;
}
.circuit_section {
padding: 12px 24px 16px;
}
.circuit_label {
margin-bottom: 2px;
font-size: 11px;
line-height: 12px;
text-transform: uppercase;
}
.circuit_warnings_box {
display: flex;
align-items: center;
}
.circuit_warnings_box label {
margin: 0;
}
.circuit_config_section:hover {
cursor: pointer;
}
.circuit_config_section {
font-size: 1rem;
}
.circuit_config {
display: flex;
align-items: center;
}
.circuit_config label {
margin: 0;
}
.circuit_inner_label {
margin-bottom: 2px;
font-size: 11px;
line-height: 12px;
text-transform: uppercase;
}
.circuit_errors_box {
padding-left: 5px;
padding-right: 5px;
word-break: break-word;
}
.circuit_feedback.success,
.circuit_feedback.error,
.circuit_feedback.warning {
white-space: pre-line;
word-wrap: break-word;
cursor: pointer;
position: relative;
margin: 0.5em 0 1em 0;
border-radius: 5px;
line-height: 20px;
padding: 8px 15px;
}
.circuit_feedback.success pre,
.circuit_feedback.error pre,
.circuit_feedback.warning pre {
white-space: pre-line;
overflow-y: hidden;
background-color: transparent;
margin: 0;
font-size: 12px;
border: 0 none;
padding: 0;
border-radius: 0;
}
.circuit_feedback.success .close,
.circuit_feedback.error .close,
.circuit_feedback.warning .close {
visibility: hidden;
white-space: pre-line;
font-weight: bold;
position: absolute;
color: hsl(0, 0%, 0%); /* black in style-guide.js */
top: 0;
right: 0;
padding: 0.5em;
}
.circuit_feedback.success a,
.circuit_feedback.error a,
.circuit_feedback.warning a {
bottom: 0;
right: 0;
}

@ -0,0 +1,27 @@
pragma circom 2.1.4;
include "circomlib/poseidon.circom";
// include "https://github.com/0xPARC/circom-secp256k1/blob/master/circuits/bigint.circom";
template Example () {
signal input a;
signal input b;
signal output c;
var unused = 4;
c <== a * b;
assert(a > 2);
component hash = Poseidon(2);
hash.inputs[0] <== a;
hash.inputs[1] <== b;
log("hash", hash.out);
}
component main { public [ a ] } = Example();
/* INPUT = {
"a": "5",
"b": "77"
} */

@ -4,7 +4,9 @@ template Multiplier2() {
signal input a;
signal input b;
signal output c;
signal output d;
c <== a*b;
d <== c*b;
}
component main = Multiplier2();

@ -6,10 +6,14 @@
<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">
<!-- <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"> -->
<link rel="stylesheet" integrity="ha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf"
crossorigin="anonymous" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css">
</head>
<body>
<div id="root"></div>
<script src="snarkjs.min.js"> </script>
<script src="https://kit.fontawesome.com/41dd021e94.js" crossorigin="anonymous"></script>
</body>
</html>

@ -1,15 +1,15 @@
{
"name": "circuit-compiler",
"kind": "provider",
"displayName": "Circuit Compiler",
"displayName": "Circom ZKP compiler",
"events": [],
"version": "2.0.0",
"methods": ["init", "parse"],
"methods": ["init", "parse", "compile", "generateR1cs"],
"canActivate": [],
"url": "",
"description": "Enables circuit compilation and computing a witness for ZK proofs",
"icon": "https://docs.circom.io/assets/images/favicon.png",
"location": "hiddenPanel",
"icon": "assets/img/circom-icon-bw-800b.webp",
"location": "sidePanel",
"documentation": "",
"repo": "https://github.com/ethereum/remix-project/tree/master/apps/circuit-compiler",
"maintainedBy": "Remix",

File diff suppressed because one or more lines are too long

@ -5,7 +5,11 @@ class ClickInstance extends EventEmitter {
command (this: NightwatchBrowser, index: number): NightwatchBrowser {
const selector = `[data-id="universalDappUiTitleExpander${index}"]`
this.api.waitForElementPresent(selector).waitForElementContainsText(selector, '', 60000).scrollAndClick(selector).perform(() => { this.emit('complete') })
this.api.waitForElementPresent({
locateStrategy: 'css selector',
selector,
timeout: 60000
}).waitForElementContainsText(selector, '', 60000).scrollAndClick(selector).perform(() => { this.emit('complete') })
return this
}
}

@ -15,7 +15,13 @@ class VerifyCallReturnValue extends EventEmitter {
}
function verifyCallReturnValue (browser: NightwatchBrowser, address: string, checks: string[] | callbackCheckVerifyCallReturnValue, done: VoidFunction) {
browser.execute(function (address: string) {
browser
.waitForElementVisible({
locateStrategy: 'css selector',
selector: '#instance' + address + ' [data-id="udapp_value"]',
timeout: 240000
})
.execute(function (address: string) {
const nodes = document.querySelectorAll('#instance' + address + ' [data-id="udapp_value"]') as NodeListOf<HTMLElement>
const ret = []
for (let k = 0; k < nodes.length; k++) {

@ -25,7 +25,6 @@ function verifyContracts (browser: NightwatchBrowser, compiledContractNames: str
.click('*[data-id="compilation-details"]')
.waitForElementVisible('*[data-id="remixui_treeviewitem_metadata"]')
.pause(2000)
.click('*[data-id="remixui_treeviewitem_metadata"]')
.waitForElementVisible('*[data-id="treeViewDivtreeViewItemcompiler"]')
.pause(2000)
.click('*[data-id="treeViewDivtreeViewItemcompiler"]')
@ -43,7 +42,6 @@ function verifyContracts (browser: NightwatchBrowser, compiledContractNames: str
.click('*[data-id="compilation-details"]')
.waitForElementVisible('*[data-id="remixui_treeviewitem_metadata"]')
.pause(2000)
.click('*[data-id="remixui_treeviewitem_metadata"]')
.assert.visible('*[data-id="treeViewDivtreeViewItemsettings"]')
.pause(2000)
.click('*[data-id="treeViewDivtreeViewItemsettings"]')

@ -291,6 +291,11 @@ module.exports = {
browser
.clickLaunchIcon('udapp')
.switchEnvironment('vm-mainnet-fork')
.waitForElementPresent({
locateStrategy: 'css selector',
selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]',
timeout: 240000
})
.executeScriptInTerminal(`web3.eth.getCode('0x180587b00c8642e2c7ac3a758712d97e6f7bdcc7')`) // mainnet contract
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x608060405260043610601f5760003560e01c80635c60da1b14603157602b565b36602b576029605f565b005b6029605f565b348015603c57600080fd5b5060436097565b6040516001600160a01b03909116815260200160405180910390f35b609560917f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b60d1565b565b600060c97f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b90565b3660008037600080366000845af43d6000803e80801560ef573d6000f35b3d6000fdfea2646970667358221220969dbb4b1d8aec2bb348e26488dc1a33b6bcf0190f567d161312ab7ca9193d8d64736f6c63430008110033', 120000)
},
@ -298,6 +303,11 @@ module.exports = {
'Should connect to the sepolia fork and run web3.eth.getCode in the terminal #group9': function (browser: NightwatchBrowser) {
browser
.switchEnvironment('vm-custom-fork')
.waitForElementPresent({
locateStrategy: 'css selector',
selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]',
timeout: 240000
})
.waitForElementPresent('[data-id="vm-custom-fork-modal-footer-ok-react"]')
.execute(() => {
(document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkNodeUrl"]') as any).focus()

@ -147,7 +147,7 @@ module.exports = {
.clickFunction('inputValue3 - transact (not payable)', { types: 'uint256[] _u', values: '["2.445e10", "13e1"]' })
.waitForElementContainsText('*[data-id="terminalJournal"]', '24450000000', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '130', 60000)
.click('*[data-id="deployAndRunClearInstances"]')
.click('*[data-id="deployAndRunClearInstances"]')
},
'Should Compile and Deploy a contract which define a custom error, the error should be logged in the terminal #group3': function (browser: NightwatchBrowser) {
@ -237,7 +237,11 @@ module.exports = {
.setSolidityCompilerVersion('soljson-v0.8.17+commit.8df45f5f.js')
.clickLaunchIcon('udapp')
.switchEnvironment('vm-mainnet-fork')
.waitForElementPresent('select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]', 30000) // wait for the udapp to load the list of accounts
.waitForElementPresent({
locateStrategy: 'css selector',
selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]',
timeout: 250000
}) // wait for the udapp to load the list of accounts
.selectContract('MyResolver')
.createContract('')
.clickInstance(0)
@ -381,7 +385,7 @@ contract C {
content: `// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.7;
/// error description
/// @param a param1
/// @param b param2
@ -393,7 +397,7 @@ contract C {
}
function g() public {
revert CustomError(2, 3, "error_string_2");
}
}
}`
}
},
@ -402,7 +406,7 @@ contract C {
content: `// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.7;
library lib {
/// error description from library
/// @param a param1 from library
@ -411,13 +415,13 @@ contract C {
error CustomError(uint a, uint b, string c);
function set() public {
revert CustomError(48, 46, "error_string_from_library");
}
}
}
}
contract D {
function h() public {
lib.set();
}
}
}`
}
},
@ -435,10 +439,10 @@ contract C {
contract Owner {
address private owner;
// event for EVM logging
event OwnerSet(address indexed oldOwner, address indexed newOwner);
// modifier to check if caller is owner
modifier isOwner() {
// If the first argument of 'require' evaluates to 'false', execution terminates and all
@ -449,7 +453,7 @@ contract C {
require(msg.sender == owner, "Caller is not owner");
_;
}
/**
* @dev Set contract deployer as owner
*/
@ -468,7 +472,7 @@ contract C {
}
/**
* @dev Return owner address
* @dev Return owner address
* @return address of owner
*/
function getOwner() external view returns (address) {
@ -503,7 +507,7 @@ contract C {
}
/**
* @dev Return value
* @dev Return value
* @return value of 'number'
*/
function retrieve() public view returns (uint256){
@ -535,7 +539,7 @@ contract C {
return resolver.addr(node);
}
}
`
`
}
}, {
"scientific_notation.sol": {
@ -567,7 +571,7 @@ contract C {
cake++;
}
}
`
`
}
}
]

@ -202,15 +202,15 @@ class FileManager extends Plugin {
* @param {string} data content to write on the file
* @returns {void}
*/
async writeFile(path, data) {
async writeFile(path, data, options?) {
try {
path = this.normalize(path)
path = this.limitPluginScope(path)
if (await this.exists(path)) {
await this._handleIsFile(path, `Cannot write file ${path}`)
return await this.setFileContent(path, data)
return await this.setFileContent(path, data, options)
} else {
const ret = await this.setFileContent(path, data)
const ret = await this.setFileContent(path, data, options)
this.emit('fileAdded', path)
return ret
}
@ -280,13 +280,13 @@ class FileManager extends Plugin {
* @param {string} path path of the file
* @returns {string} content of the file
*/
async readFile(path) {
async readFile(path, options?) {
try {
path = this.normalize(path)
path = this.limitPluginScope(path)
await this._handleExists(path, `Cannot read file ${path}`)
await this._handleIsFile(path, `Cannot read file ${path}`)
return this.getFileContent(path)
return this.getFileContent(path, options)
} catch (e) {
throw new Error(e)
}
@ -604,7 +604,7 @@ class FileManager extends Plugin {
return path ? path[1] : '/'
}
getFileContent(path) {
getFileContent(path, options?) {
const provider = this.fileProviderOf(path)
if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` })
@ -614,11 +614,11 @@ class FileManager extends Plugin {
provider.get(path, (err, content) => {
if (err) reject(err)
resolve(content)
})
}, options)
})
}
async setFileContent(path, content) {
async setFileContent(path, content, options?) {
if (this.currentRequest) {
const canCall = await this.askUserPermission(`writeFile`, `modifying ${path} ...`)
const required = this.appManager.isRequired(this.currentRequest.from)
@ -627,10 +627,10 @@ class FileManager extends Plugin {
this.call('notification', 'toast', fileChangedToastMsg(this.currentRequest.from, path))
}
}
return await this._setFileInternal(path, content)
return await this._setFileInternal(path, content, options)
}
_setFileInternal(path, content) {
_setFileInternal(path, content, options?) {
const provider = this.fileProviderOf(path)
if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` })
// TODO : Add permission
@ -641,7 +641,7 @@ class FileManager extends Plugin {
this.syncEditor(path)
this.emit('fileSaved', path)
resolve(true)
})
}, options)
})
}

@ -87,12 +87,12 @@ class FileProvider {
cb()
}
async get (path, cb) {
async get (path, cb, options = { encoding: 'utf8' }) {
cb = cb || function () { /* do nothing. */ }
path = this.getPathFromUrl(path) || path // ensure we actually use the normalized path from here
var unprefixedpath = this.removePrefix(path)
try {
const content = await window.remixFileSystem.readFile(unprefixedpath, 'utf8')
const content = await window.remixFileSystem.readFile(unprefixedpath, options)
if (cb) cb(null, content)
return content
} catch (err) {
@ -101,17 +101,17 @@ class FileProvider {
}
}
async set (path, content, cb) {
async set (path, content, cb, options = { encoding: 'utf8' }) {
cb = cb || function () { /* do nothing. */ }
var unprefixedpath = this.removePrefix(path)
const exists = await window.remixFileSystem.exists(unprefixedpath)
if (exists && await window.remixFileSystem.readFile(unprefixedpath, 'utf8') === content) {
if (exists && await window.remixFileSystem.readFile(unprefixedpath, options) === content) {
if (cb) cb()
return null
}
await this.createDir(path.substr(0, path.lastIndexOf('/')))
try {
await window.remixFileSystem.writeFile(unprefixedpath, content, 'utf8')
await window.remixFileSystem.writeFile(unprefixedpath, content, options)
} catch (e) {
if (cb) cb(e)
return false

@ -18,7 +18,7 @@ export class MainnetForkVMProvider extends BasicVMProvider {
)
this.blockchain = blockchain
this.fork = 'shanghai'
this.nodeUrl = 'https://mainnet.infura.io/v3/08b2a484451e4635a28b3d8234f24332'
this.nodeUrl = 'https://mainnet.infura.io/v3/7eed077ab9ee45eebbb3f053af9ecb29'
this.blockNumber = 'latest'
}

@ -0,0 +1,15 @@
{
"circuit.compiler": "Compiler",
"circuit.autoCompile": "Auto compile",
"circuit.hideWarnings": "Hide warnings",
"circuit.advancedConfigurations": "Advanced Configurations",
"circuit.compilerConfiguration": "Compiler configuration",
"circuit.prime": "Prime",
"circuit.useConfigurationFile": "Use configuration file",
"circuit.compile": "Compile",
"circuit.noFileSelected": "no file selected",
"circuit.generateR1cs": "Generate R1CS",
"circuit.computeWitness": "Compute Witness",
"circuit.signalInput": "Signal Input",
"circuit.compute": "Compute"
}

@ -103,6 +103,7 @@
"filePanel.mintable": "Mintable",
"filePanel.burnable": "Burnable",
"filePanel.pausable": "Pausable",
"filePanel.semaphore": "Semaphore",
"filePanel.transparent": "Transparent",
"filePanel.initGitRepoTitle": "Check option to initialize workspace as a new git repository",
"filePanel.switchToBranchTitle1": "Checkout new branch from remote branch",

@ -13,6 +13,7 @@ import permissionHandlerJson from './permissionHandler.json';
import solUmlGenJson from './solUmlGen.json'
import remixAppJson from './remixApp.json'
import remixUiTabsJson from './remixUiTabs.json'
import circuitJson from './circuit.json';
export default {
...debuggerJson,
@ -30,4 +31,5 @@ export default {
...solUmlGenJson,
...remixAppJson,
...remixUiTabsJson,
...circuitJson
}

@ -0,0 +1,15 @@
{
"circuit.compiler": "Compiler",
"circuit.autoCompile": "Auto compile",
"circuit.hideWarnings": "Hide warnings",
"circuit.advancedConfigurations": "Advanced Configurations",
"circuit.compilerConfiguration": "Compiler configuration",
"circuit.prime": "Prime",
"circuit.useConfigurationFile": "Use configuration file",
"circuit.compile": "Compile",
"circuit.noFileSelected": "no file selected",
"circuit.generateR1cs": "Generate R1CS",
"circuit.computeWitness": "Compute Witness",
"circuit.signalInput": "Signal Input",
"circuit.compute": "Compute"
}

@ -0,0 +1,15 @@
{
"circuit.compiler": "Compiler",
"circuit.autoCompile": "Auto compile",
"circuit.hideWarnings": "Hide warnings",
"circuit.advancedConfigurations": "Advanced Configurations",
"circuit.compilerConfiguration": "Compiler configuration",
"circuit.prime": "Prime",
"circuit.useConfigurationFile": "Use configuration file",
"circuit.compile": "Compile",
"circuit.noFileSelected": "no file selected",
"circuit.generateR1cs": "Generate R1CS",
"circuit.computeWitness": "Compute Witness",
"circuit.signalInput": "Signal Input",
"circuit.compute": "Compute"
}

@ -0,0 +1,16 @@
{
"circuit-compiler.displayName": "Circuit 编译器",
"circuit.compiler": "Compiler",
"circuit.autoCompile": "自动编译",
"circuit.hideWarnings": "隐藏警告",
"circuit.advancedConfigurations": "高级配置",
"circuit.compilerConfiguration": "编译器配置",
"circuit.prime": "质数",
"circuit.useConfigurationFile": "使用配置文件",
"circuit.compile": "编译",
"circuit.noFileSelected": "未选中文件",
"circuit.generateR1cs": "生成R1CS",
"circuit.computeWitness": "证人计算器",
"circuit.signalInput": "输入信号",
"circuit.compute": "计算"
}

@ -14,6 +14,7 @@ import solUmlGenJson from './solUmlGen.json'
import remixAppJson from './remixApp.json'
import remixUiTabsJson from './remixUiTabs.json'
import enJson from '../en';
import circuitJson from './circuit.json';
// There may have some un-translated content. Always fill in the gaps with EN JSON.
// No need for a defaultMessage prop when render a FormattedMessage component.
@ -33,4 +34,5 @@ export default Object.assign({}, enJson, {
...solUmlGenJson,
...remixAppJson,
...remixUiTabsJson,
...circuitJson
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

File diff suppressed because one or more lines are too long

@ -113,7 +113,8 @@ export function isNative(name) {
'injected-ephemery-testnet-provider',
'injected',
'doc-gen',
'doc-viewer'
'doc-viewer',
'circuit-compiler'
]
return nativePlugins.includes(name) || requiredModules.includes(name)
}

@ -81,7 +81,7 @@ export const getPathIcon = (path: string) => {
? 'small fak fa-ts-logo' : path.endsWith('.tsc')
? 'fad fa-brackets-curly' : path.endsWith('.cairo')
? 'small fak fa-cairo' : path.endsWith('.circom')
? 'fak fa-circom-plug1' : 'far fa-file'
? 'fak fa-circom' : 'far fa-file'
}
export const isNumeric = (value) => {

@ -1,6 +1,8 @@
import { CopyToClipboard } from '@remix-ui/clipboard'
import { CustomTooltip } from '@remix-ui/helper'
import { TreeView, TreeViewItem } from '@remix-ui/tree-view'
import { ContractPropertyName } from '@remix-ui/solidity-compiler'
import React from 'react'
import { useIntl } from 'react-intl'
@ -32,7 +34,7 @@ export function RemixUiCompileDetails({ plugin, contractProperties, selectedCont
</div>
<div className="remixui_detailsJSON">
<TreeView>
{Object.keys(contractProperties).map((propertyName, index) => {
{Object.keys(contractProperties).map((propertyName: ContractPropertyName, index) => {
const copyDetails = (
<span className="remixui_copyDetails">
<CopyToClipboard tip={intl.formatMessage({id: 'solidity.copy'})} content={contractProperties[propertyName]} direction="top" />
@ -59,6 +61,8 @@ export function RemixUiCompileDetails({ plugin, contractProperties, selectedCont
{propertyName} {copyDetails} {questionMark}
</div>
}
expand={propertyName === 'metadata' || propertyName === 'bytecode' ? true : false}
iconY='fas fa-caret-down'
>
{insertValue(contractProperties, propertyName)}
</TreeViewItem>

@ -1,4 +1,5 @@
export * from './lib/solidity-compiler'
export * from './lib/logic'
export * from './lib/logic/flattenerUtilities'
export * from './lib/api/compiler-api'
export * from './lib/api/compiler-api'
export * from './lib/types'

@ -1,6 +1,6 @@
import React, {useState, useEffect} from 'react' // eslint-disable-line
import {FormattedMessage, useIntl} from 'react-intl'
import {ContractSelectionProps} from './types'
import {ContractPropertyName, ContractSelectionProps} from './types'
import {PublishToStorage} from '@remix-ui/publish-to-storage' // eslint-disable-line
import {TreeView, TreeViewItem} from '@remix-ui/tree-view' // eslint-disable-line
import {CopyToClipboard} from '@remix-ui/clipboard' // eslint-disable-line
@ -122,7 +122,7 @@ export const ContractSelection = (props: ContractSelectionProps) => {
return ret
}
const insertValue = (details, propertyName) => {
const insertValue = (details, propertyName: ContractPropertyName) => {
let node
if (propertyName === 'web3Deploy' || propertyName === 'name' || propertyName === 'Assembly') {
node = <pre>{details[propertyName]}</pre>
@ -197,7 +197,7 @@ export const ContractSelection = (props: ContractSelectionProps) => {
const log = (
<div className="remixui_detailsJSON">
<TreeView>
{Object.keys(contractProperties).map((propertyName, index) => {
{Object.keys(contractProperties).map((propertyName: ContractPropertyName, index) => {
const copyDetails = (
<span className="remixui_copyDetails">
<CopyToClipboard tip={intl.formatMessage({id: 'solidity.copy'})} content={contractProperties[propertyName]} direction="top" />

@ -53,3 +53,7 @@ export interface CompilationDetails {
export interface ContractsFile {
[currentFile: string]: CompilationDetails
}
export type ContractPropertyName = 'compilerInput' | 'name' | 'metadata' | 'bytecode' | 'abi' | 'storageLayout'
| 'web3Deploy' | 'metadataHash' | 'functionHashes' | 'gasEstimates' | 'devdoc' | 'userdoc' | 'Runtime Bytecode'
| 'Assembly'

@ -179,6 +179,9 @@ export const TabsUI = (props: TabsUIProps) => {
} else if (tabsState.currentExt === 'sol' || tabsState.currentExt === 'yul') {
await props.plugin.call('solidity', 'compile', path)
_paq.push(['trackEvent', 'editor', 'clickRunFromEditor', tabsState.currentExt])
} else if (tabsState.currentExt === 'circom') {
await props.plugin.call('circuit-compiler', 'compile', path)
_paq.push(['trackEvent', 'editor', 'clickRunFromEditor', tabsState.currentExt])
}
}}
>
@ -189,7 +192,7 @@ export const TabsUI = (props: TabsUIProps) => {
<span>
{tabsState.currentExt === 'js' || tabsState.currentExt === 'ts' ? (
<FormattedMessage id="remixUiTabs.tooltipText1" />
) : tabsState.currentExt === 'sol' || tabsState.currentExt === 'yul' ? (
) : tabsState.currentExt === 'sol' || tabsState.currentExt === 'yul' || tabsState.currentExt === 'circom' ? (
<FormattedMessage id="remixUiTabs.tooltipText2" />
) : (
<FormattedMessage id="remixUiTabs.tooltipText3" />

@ -1,7 +1,7 @@
import { fileDecoration } from '@remix-ui/file-decorators'
import { extractParentFromKey } from '@remix-ui/helper'
import React from 'react'
import { action, WorkspaceTemplate } from '../types'
import { action, FileTree, WorkspaceTemplate } from '../types'
import { ROOT_PATH } from '../utils/constants'
import { displayNotification, displayPopUp, fileAddedSuccess, fileRemovedSuccess, fileRenamedSuccess, folderAddedSuccess, loadLocalhostError, loadLocalhostRequest, loadLocalhostSuccess, removeContextMenuItem, removeFocus, rootFolderChangedSuccess, setContextMenuItem, setMode, setReadOnlyMode, setFileDecorationSuccess } from './payload'
import { addInputField, createWorkspace, deleteWorkspace, fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile } from './workspace'
@ -177,8 +177,8 @@ const folderAdded = async (folderPath: string) => {
const provider = plugin.fileManager.currentFileProvider()
const path = extractParentFromKey(folderPath) || ROOT_PATH
const promise = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree) => {
const promise: Promise<FileTree> = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree: FileTree) => {
if (error) console.error(error)
resolve(fileTree)
})
@ -200,8 +200,8 @@ const fileRemoved = async (removePath: string) => {
const fileRenamed = async (oldPath: string) => {
const provider = plugin.fileManager.currentFileProvider()
const path = extractParentFromKey(oldPath) || ROOT_PATH
const promise = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree) => {
const promise: Promise<FileTree> = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree: FileTree) => {
if (error) console.error(error)
resolve(fileTree)

@ -9,6 +9,7 @@ import { QueryParams } from '@remix-project/remix-lib'
import { fetchContractFromEtherscan } from '@remix-project/core-plugin' // eslint-disable-line
import JSZip from 'jszip'
import isElectron from 'is-electron'
import { Actions, FileTree } from '../types'
export * from './events'
export * from './workspace'
@ -16,7 +17,7 @@ export * from './workspace'
const queryParams = new QueryParams()
const _paq = window._paq = window._paq || []
let plugin, dispatch: React.Dispatch<any>
let plugin, dispatch: React.Dispatch<Actions>
export type UrlParametersType = {
gist: string,
@ -43,7 +44,7 @@ const basicWorkspaceInit = async (workspaces: { name: string; isGitRepo: boolean
}
}
export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React.Dispatch<any>) => {
export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React.Dispatch<Actions>) => {
if (filePanelPlugin) {
plugin = filePanelPlugin
dispatch = reducerDispatch
@ -144,18 +145,18 @@ export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React.
export const fetchDirectory = async (path: string) => {
const provider = plugin.fileManager.currentFileProvider()
const promise = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree) => {
provider.resolveDirectory(path, (error, fileTree: FileTree) => {
if (error) console.error(error)
resolve(fileTree)
})
})
dispatch(fetchDirectoryRequest(promise))
promise.then((fileTree) => {
dispatch(fetchDirectoryRequest())
promise.then((fileTree: FileTree) => {
dispatch(fetchDirectorySuccess(path, fileTree))
}).catch((error) => {
dispatch(fetchDirectoryError({ error }))
}).catch((error: ErrorEvent) => {
dispatch(fetchDirectoryError(error.message))
})
return promise
}

@ -1,292 +1,300 @@
import { fileDecoration } from '@remix-ui/file-decorators'
import { action } from '../types'
import { Action, ActionPayloadTypes, FileTree, WorkspaceElement, action } from '../types'
export const setCurrentWorkspace = (workspace: { name: string; isGitRepo: boolean; }) => {
export const setCurrentWorkspace = (workspace: { name: string; isGitRepo: boolean; }): Action<'SET_CURRENT_WORKSPACE'> => {
return {
type: 'SET_CURRENT_WORKSPACE',
payload: workspace
}
}
export const setWorkspaces = (workspaces: { name: string; isGitRepo: boolean; }[]) => {
export const setWorkspaces = (workspaces: { name: string; isGitRepo: boolean; }[]): Action<'SET_WORKSPACES'> => {
return {
type: 'SET_WORKSPACES',
payload: workspaces
}
}
export const setMode = (mode: 'browser' | 'localhost') => {
export const setMode = (mode: 'browser' | 'localhost'): Action<'SET_MODE'> => {
return {
type: 'SET_MODE',
payload: mode
}
}
export const fetchDirectoryError = (error: any) => {
export const fetchDirectoryError = (error: string): Action<'FETCH_DIRECTORY_ERROR'> => {
return {
type: 'FETCH_DIRECTORY_ERROR',
payload: error
}
}
export const fetchDirectoryRequest = (promise: Promise<any>) => {
export const fetchDirectoryRequest = (): Action<'FETCH_DIRECTORY_REQUEST'> => {
return {
type: 'FETCH_DIRECTORY_REQUEST',
payload: promise
payload: undefined
}
}
export const fetchDirectorySuccess = (path: string, fileTree) => {
export const fetchDirectorySuccess = (path: string, fileTree: FileTree): Action<'FETCH_DIRECTORY_SUCCESS'> => {
return {
type: 'FETCH_DIRECTORY_SUCCESS',
payload: { path, fileTree }
}
}
export const displayNotification = (title: string, message: string, labelOk: string, labelCancel: string, actionOk?: (...args) => void, actionCancel?: (...args) => void) => {
export const displayNotification = (title: string, message: string, labelOk: string, labelCancel: string, actionOk?: (...args) => void, actionCancel?: (...args) => void): Action<'DISPLAY_NOTIFICATION'> => {
return {
type: 'DISPLAY_NOTIFICATION',
payload: { title, message, labelOk, labelCancel, actionOk, actionCancel }
}
}
export const hideNotification = () => {
export const hideNotification = (): Action<'HIDE_NOTIFICATION'> => {
return {
type: 'HIDE_NOTIFICATION'
type: 'HIDE_NOTIFICATION',
payload: null
}
}
export const fileAddedSuccess = (filePath: string) => {
export const fileAddedSuccess = (filePath: string): Action<'FILE_ADDED_SUCCESS'> => {
return {
type: 'FILE_ADDED_SUCCESS',
payload: filePath
}
}
export const folderAddedSuccess = (path: string, folderPath: string, fileTree) => {
export const folderAddedSuccess = (path: string, folderPath: string, fileTree: FileTree): Action<'FOLDER_ADDED_SUCCESS'> => {
return {
type: 'FOLDER_ADDED_SUCCESS',
payload: { path, folderPath, fileTree }
}
}
export const fileRemovedSuccess = (removePath: string) => {
export const fileRemovedSuccess = (removePath: string): Action<'FILE_REMOVED_SUCCESS'> => {
return {
type: 'FILE_REMOVED_SUCCESS',
payload: removePath
}
}
export const fileRenamedSuccess = (path: string, oldPath: string, fileTree) => {
export const fileRenamedSuccess = (path: string, oldPath: string, fileTree: FileTree): Action<'FILE_RENAMED_SUCCESS'> => {
return {
type: 'FILE_RENAMED_SUCCESS',
payload: { path, oldPath, fileTree }
}
}
export const rootFolderChangedSuccess = (path: string) => {
export const rootFolderChangedSuccess = (path: string): Action<'ROOT_FOLDER_CHANGED'> => {
return {
type: 'ROOT_FOLDER_CHANGED',
payload: path
}
}
export const addInputFieldSuccess = (path: string, fileTree, type: 'file' | 'folder' | 'gist') => {
export const addInputFieldSuccess = (path: string, fileTree: FileTree, type: 'file' | 'folder'): Action<'ADD_INPUT_FIELD'> => {
return {
type: 'ADD_INPUT_FIELD',
payload: { path, fileTree, type }
}
}
export const removeInputFieldSuccess = (path: string) => {
export const removeInputFieldSuccess = (path: string): Action<'REMOVE_INPUT_FIELD'> => {
return {
type: 'REMOVE_INPUT_FIELD',
payload: { path }
}
}
export const setReadOnlyMode = (mode: boolean) => {
export const setReadOnlyMode = (mode: boolean): Action<'SET_READ_ONLY_MODE'> => {
return {
type: 'SET_READ_ONLY_MODE',
payload: mode
}
}
export const createWorkspaceError = (error: any) => {
export const createWorkspaceError = (error: string): Action<'CREATE_WORKSPACE_ERROR'> => {
return {
type: 'CREATE_WORKSPACE_ERROR',
payload: error
}
}
export const createWorkspaceRequest = (promise: Promise<any>) => {
export const createWorkspaceRequest = (): Action<'CREATE_WORKSPACE_REQUEST'> => {
return {
type: 'CREATE_WORKSPACE_REQUEST',
payload: promise
payload: null
}
}
export const createWorkspaceSuccess = (workspaceName: { name: string; isGitRepo: boolean; branches?: { remote: any; name: string; }[], currentBranch?: string }) => {
export const createWorkspaceSuccess = (workspaceName: ActionPayloadTypes['CREATE_WORKSPACE_SUCCESS']): Action<'CREATE_WORKSPACE_SUCCESS'> => {
return {
type: 'CREATE_WORKSPACE_SUCCESS',
payload: workspaceName
}
}
export const fetchWorkspaceDirectoryError = (error: any) => {
export const fetchWorkspaceDirectoryError = (error: string): Action<'FETCH_WORKSPACE_DIRECTORY_ERROR'> => {
return {
type: 'FETCH_WORKSPACE_DIRECTORY_ERROR',
payload: error
}
}
export const fetchWorkspaceDirectoryRequest = (promise: Promise<any>) => {
export const fetchWorkspaceDirectoryRequest = (): Action<'FETCH_WORKSPACE_DIRECTORY_REQUEST'> => {
return {
type: 'FETCH_WORKSPACE_DIRECTORY_REQUEST',
payload: promise
payload: null
}
}
export const fetchWorkspaceDirectorySuccess = (path: string, fileTree) => {
export const fetchWorkspaceDirectorySuccess = (path: string, fileTree: FileTree): Action<'FETCH_WORKSPACE_DIRECTORY_SUCCESS'> => {
return {
type: 'FETCH_WORKSPACE_DIRECTORY_SUCCESS',
payload: { path, fileTree }
}
}
export const setRenameWorkspace = (oldName: string, workspaceName: string) => {
export const setRenameWorkspace = (oldName: string, workspaceName: string): Action<'RENAME_WORKSPACE'> => {
return {
type: 'RENAME_WORKSPACE',
payload: { oldName, workspaceName }
}
}
export const setDeleteWorkspace = (workspaceName: string) => {
export const setDeleteWorkspace = (workspaceName: string): Action<'DELETE_WORKSPACE'> => {
return {
type: 'DELETE_WORKSPACE',
payload: workspaceName
}
}
export const displayPopUp = (message: string) => {
export const displayPopUp = (message: string): Action<'DISPLAY_POPUP_MESSAGE'> => {
return {
type: 'DISPLAY_POPUP_MESSAGE',
payload: message
}
}
export const hidePopUp = () => {
export const hidePopUp = (): Action<'HIDE_POPUP_MESSAGE'> => {
return {
type: 'HIDE_POPUP_MESSAGE'
type: 'HIDE_POPUP_MESSAGE',
payload: null
}
}
export const focusElement = (elements: { key: string, type: 'file' | 'folder' | 'gist' }[]) => {
export const focusElement = (elements: { key: string, type: WorkspaceElement }[]): Action<'SET_FOCUS_ELEMENT'> => {
return {
type: 'SET_FOCUS_ELEMENT',
payload: elements
}
}
export const removeFocus = (name: string) => {
export const removeFocus = (name: string): Action<'REMOVE_FOCUS_ELEMENT'> => {
return {
type: 'REMOVE_FOCUS_ELEMENT',
payload: name
}
}
export const setContextMenuItem = (item: action) => {
export const setContextMenuItem = (item: action): Action<'SET_CONTEXT_MENU_ITEM'> => {
return {
type: 'SET_CONTEXT_MENU_ITEM',
payload: item
}
}
export const removeContextMenuItem = (plugin) => {
export const removeContextMenuItem = (plugin: { name: string }): Action<'REMOVE_CONTEXT_MENU_ITEM'> => {
return {
type: 'REMOVE_CONTEXT_MENU_ITEM',
payload: plugin
}
}
export const setExpandPath = (paths: string[]) => {
export const setExpandPath = (paths: string[]): Action<'SET_EXPAND_PATH'> => {
return {
type: 'SET_EXPAND_PATH',
payload: paths
}
}
export const loadLocalhostError = (error: any) => {
export const loadLocalhostError = (error: string): Action<'LOAD_LOCALHOST_ERROR'> => {
return {
type: 'LOAD_LOCALHOST_ERROR',
payload: error
}
}
export const loadLocalhostRequest = () => {
export const loadLocalhostRequest = (): Action<'LOAD_LOCALHOST_REQUEST'> => {
return {
type: 'LOAD_LOCALHOST_REQUEST'
type: 'LOAD_LOCALHOST_REQUEST',
payload: null
}
}
export const loadLocalhostSuccess = () => {
export const loadLocalhostSuccess = (): Action<'LOAD_LOCALHOST_SUCCESS'> => {
return {
type: 'LOAD_LOCALHOST_SUCCESS'
type: 'LOAD_LOCALHOST_SUCCESS',
payload: null
}
}
export const fsInitializationCompleted = () => {
export const fsInitializationCompleted = (): Action<'FS_INITIALIZATION_COMPLETED'> => {
return {
type: 'FS_INITIALIZATION_COMPLETED'
type: 'FS_INITIALIZATION_COMPLETED',
payload: null
}
}
export const setFileDecorationSuccess = (items: fileDecoration[]) => {
export const setFileDecorationSuccess = (items: fileDecoration[]): Action<'SET_FILE_DECORATION_SUCCESS'> => {
return {
type: 'SET_FILE_DECORATION_SUCCESS',
payload: items
}
}
export const cloneRepositoryRequest = () => {
export const cloneRepositoryRequest = (): Action<'CLONE_REPOSITORY_REQUEST'> => {
return {
type: 'CLONE_REPOSITORY_REQUEST'
type: 'CLONE_REPOSITORY_REQUEST',
payload: null
}
}
export const cloneRepositorySuccess = () => {
export const cloneRepositorySuccess = (): Action<'CLONE_REPOSITORY_SUCCESS'> => {
return {
type: 'CLONE_REPOSITORY_SUCCESS'
type: 'CLONE_REPOSITORY_SUCCESS',
payload: null
}
}
export const cloneRepositoryFailed = () => {
export const cloneRepositoryFailed = (): Action<'CLONE_REPOSITORY_FAILED'> => {
return {
type: 'CLONE_REPOSITORY_FAILED'
type: 'CLONE_REPOSITORY_FAILED',
payload: null
}
}
export const setCurrentWorkspaceBranches = (branches?: { remote: any, name: string }[]) => {
export const setCurrentWorkspaceBranches = (branches?: { remote: any, name: string }[]): Action<'SET_CURRENT_WORKSPACE_BRANCHES'> => {
return {
type: 'SET_CURRENT_WORKSPACE_BRANCHES',
payload: branches
}
}
export const setCurrentWorkspaceCurrentBranch = (currentBranch?: string) => {
export const setCurrentWorkspaceCurrentBranch = (currentBranch?: string): Action<'SET_CURRENT_WORKSPACE_CURRENT_BRANCH'> => {
return {
type: 'SET_CURRENT_WORKSPACE_CURRENT_BRANCH',
payload: currentBranch
}
}
export const setCurrentWorkspaceIsGitRepo = (isRepo: boolean) => {
export const setCurrentWorkspaceIsGitRepo = (isRepo: boolean): Action<'SET_CURRENT_WORKSPACE_IS_GITREPO'> => {
return {
type: 'SET_CURRENT_WORKSPACE_IS_GITREPO',
payload: isRepo
}
}
export const setGitConfig = (config: {username: string, token: string, email: string}) => {
export const setGitConfig = (config: {username: string, token: string, email: string}): Action<'SET_GIT_CONFIG'> => {
return {
type: 'SET_GIT_CONFIG',
payload: config

@ -28,7 +28,7 @@ import {
} from './payload'
import { addSlash, checkSlash, checkSpecialChars } from '@remix-ui/helper'
import { JSONStandardInput, WorkspaceTemplate } from '../types'
import { FileTree, JSONStandardInput, WorkspaceTemplate } from '../types'
import { QueryParams } from '@remix-project/remix-lib'
import * as templateWithContent from '@remix-project/remix-ws-templates'
import { ROOT_PATH, slitherYml, solTestYml, tsSolTestYml } from '../utils/constants'
@ -82,8 +82,8 @@ export const setPlugin = (filePanelPlugin, reducerDispatch) => {
export const addInputField = async (type: 'file' | 'folder', path: string, cb?: (err: Error, result?: string | number | boolean | Record<string, any>) => void) => {
const provider = plugin.fileManager.currentFileProvider()
const promise = new Promise((resolve, reject) => {
provider.resolveDirectory(path, (error, fileTree) => {
const promise: Promise<FileTree> = new Promise((resolve, reject) => {
provider.resolveDirectory(path, (error, fileTree: FileTree) => {
if (error) {
cb && cb(error)
return reject(error)
@ -119,9 +119,8 @@ export const createWorkspace = async (
) => {
await plugin.fileManager.closeAllFiles()
const promise = createWorkspaceTemplate(workspaceName, workspaceTemplateName)
dispatch(createWorkspaceRequest(promise))
promise
.then(async () => {
dispatch(createWorkspaceRequest())
promise.then(async () => {
dispatch(createWorkspaceSuccess({ name: workspaceName, isGitRepo }))
await plugin.setWorkspace({ name: workspaceName, isLocalhost: false })
await plugin.workspaceCreated(workspaceName)
@ -175,7 +174,7 @@ export const createWorkspace = async (
await plugin.setWorkspaces(await getWorkspaces())
})
.catch((error) => {
dispatch(createWorkspaceError({ error }))
dispatch(createWorkspaceError(error.message))
cb && cb(error)
})
return promise
@ -338,20 +337,20 @@ export const workspaceExists = async (name: string) => {
export const fetchWorkspaceDirectory = async (path: string) => {
if (!path) return
const provider = plugin.fileManager.currentFileProvider()
const promise = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree) => {
const promise: Promise<FileTree> = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree: FileTree) => {
if (error) console.error(error)
resolve(fileTree)
})
})
dispatch(fetchWorkspaceDirectoryRequest(promise))
dispatch(fetchWorkspaceDirectoryRequest())
promise
.then((fileTree) => {
dispatch(fetchWorkspaceDirectorySuccess(path, fileTree))
})
.catch((error) => {
dispatch(fetchWorkspaceDirectoryError({ error }))
dispatch(fetchWorkspaceDirectoryError(error.message))
})
return promise
}

@ -3,7 +3,7 @@ import {useIntl} from 'react-intl'
import {TreeView} from '@remix-ui/tree-view' // eslint-disable-line
import {FileExplorerMenu} from './file-explorer-menu' // eslint-disable-line
import {FileExplorerContextMenu} from './file-explorer-context-menu' // eslint-disable-line
import {FileExplorerProps, FileType, WorkSpaceState} from '../types'
import {FileExplorerProps, FileType, WorkSpaceState, WorkspaceElement} from '../types'
import '../css/file-explorer.css'
import {checkSpecialChars, extractNameFromKey, extractParentFromKey, joinPath} from '@remix-ui/helper'
@ -151,7 +151,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
)
}
const handleClickFile = (path: string, type: 'folder' | 'file' | 'gist') => {
const handleClickFile = (path: string, type: WorkspaceElement) => {
if (!state.ctrlKey) {
props.dispatchHandleClickFile(path, type)
} else {

@ -1,6 +1,6 @@
// eslint-disable-next-line no-use-before-define
import React, {SyntheticEvent, useEffect, useState} from 'react'
import {FileType} from '../types'
import {FileType, WorkspaceElement} from '../types'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import {TreeView, TreeViewItem} from '@remix-ui/tree-view'
import {getPathIcon} from '@remix-ui/helper'
@ -14,7 +14,7 @@ export interface RenderFileProps {
file: FileType
index: number
focusEdit: {element: string; type: string; isNew: boolean; lastEdit: string}
focusElement: {key: string; type: 'file' | 'folder' | 'gist'}[]
focusElement: {key: string; type: WorkspaceElement}[]
focusContext: {element: string; x: number; y: number; type: string}
ctrlKey: boolean
expandPath: string[]

@ -1,12 +1,8 @@
import {extractNameFromKey} from '@remix-ui/helper'
import {action, FileType} from '../types'
import {action, Actions, FileType, WorkspaceElement} from '../types'
import * as _ from 'lodash'
import {fileDecoration} from '@remix-ui/file-decorators'
import {ROOT_PATH} from '../utils/constants'
interface Action {
type: string
payload: any
}
export interface BrowserState {
browser: {
currentWorkspace: string
@ -63,7 +59,7 @@ export interface BrowserState {
readonly: boolean
popup: string
focusEdit: string
focusElement: {key: string; type: 'file' | 'folder' | 'gist'}[]
focusElement: {key: string; type: WorkspaceElement}[]
initializingFS: boolean
gitConfig: {username: string; email: string; token: string}
}
@ -121,15 +117,10 @@ export const browserInitialState: BrowserState = {
gitConfig: {username: '', email: '', token: ''}
}
export const browserReducer = (state = browserInitialState, action: Action) => {
export const browserReducer = (state = browserInitialState, action: Actions) => {
switch (action.type) {
case 'SET_CURRENT_WORKSPACE': {
const payload = action.payload as {
name: string
isGitRepo: boolean
branches?: {remote: any; name: string}[]
currentBranch?: string
}
const payload = action.payload
const workspaces = state.browser.workspaces.find(
({name}) => name === payload.name
)
@ -147,12 +138,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'SET_WORKSPACES': {
const payload = action.payload as {
name: string
isGitRepo: boolean
branches?: {remote: any; name: string}[]
currentBranch?: string
}[]
const payload = action.payload
return {
...state,
@ -164,7 +150,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'SET_MODE': {
const payload = action.payload as 'browser' | 'localhost'
const payload = action.payload
return {
...state,
@ -191,7 +177,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'FETCH_DIRECTORY_SUCCESS': {
const payload = action.payload as {path: string; fileTree}
const payload = action.payload
return {
...state,
@ -255,7 +241,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'FETCH_WORKSPACE_DIRECTORY_SUCCESS': {
const payload = action.payload as {path: string; fileTree}
const payload = action.payload
return {
...state,
@ -302,14 +288,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'DISPLAY_NOTIFICATION': {
const payload = action.payload as {
title: string
message: string
actionOk: () => void
actionCancel: () => void
labelOk: string
labelCancel: string
}
const payload = action.payload
return {
...state,
@ -335,7 +314,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'FILE_ADDED_SUCCESS': {
const payload = action.payload as string
const payload = action.payload
return {
...state,
@ -365,11 +344,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'FOLDER_ADDED_SUCCESS': {
const payload = action.payload as {
path: string
folderPath: string
fileTree
}
const payload = action.payload
return {
...state,
@ -404,7 +379,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'FILE_REMOVED_SUCCESS': {
const payload = action.payload as string
const payload = action.payload
return {
...state,
@ -446,11 +421,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'ADD_INPUT_FIELD': {
const payload = action.payload as {
path: string
fileTree
type: 'file' | 'folder'
}
const payload = action.payload
return {
...state,
@ -473,7 +444,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'REMOVE_INPUT_FIELD': {
const payload = action.payload as {path: string; fileTree}
const payload = action.payload
return {
...state,
@ -496,7 +467,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'SET_READ_ONLY_MODE': {
const payload = action.payload as boolean
const payload = action.payload
return {
...state,
@ -505,11 +476,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'FILE_RENAMED_SUCCESS': {
const payload = action.payload as {
path: string
oldPath: string
fileTree
}
const payload = action.payload
return {
...state,
@ -543,12 +510,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'CREATE_WORKSPACE_SUCCESS': {
const payload = action.payload as {
name: string
isGitRepo: boolean
branches?: {remote: any; name: string}[]
currentBranch?: string
}
const payload = action.payload
const workspaces = state.browser.workspaces.find(
({name}) => name === payload.name
)
@ -581,7 +543,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'RENAME_WORKSPACE': {
const payload = action.payload as {oldName: string; workspaceName: string}
const payload = action.payload
let renamedWorkspace
const workspaces = state.browser.workspaces.filter(
({name, isGitRepo, branches, currentBranch}) => {
@ -611,7 +573,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'DELETE_WORKSPACE': {
const payload = action.payload as string
const payload = action.payload
const workspaces = state.browser.workspaces.filter(
({name}) => name && name !== payload
)
@ -626,7 +588,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'DISPLAY_POPUP_MESSAGE': {
const payload = action.payload as string
const payload = action.payload
return {
...state,
@ -642,10 +604,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'SET_FOCUS_ELEMENT': {
const payload = action.payload as {
key: string
type: 'file' | 'folder' | 'gist'
}[]
const payload = action.payload
return {
...state,
@ -654,7 +613,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'REMOVE_FOCUS_ELEMENT': {
const payload: string = action.payload
const payload = action.payload
return {
...state,
@ -665,7 +624,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'SET_CONTEXT_MENU_ITEM': {
const payload = action.payload as action
const payload = action.payload
return {
...state,
@ -801,7 +760,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'SET_CURRENT_WORKSPACE_BRANCHES': {
const payload: {remote: any; name: string}[] = action.payload
const payload = action.payload
return {
...state,
@ -817,7 +776,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'SET_CURRENT_WORKSPACE_CURRENT_BRANCH': {
const payload: string = action.payload
const payload = action.payload
return {
...state,
@ -833,7 +792,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'SET_CURRENT_WORKSPACE_IS_GITREPO': {
const payload: boolean = action.payload
const payload = action.payload
return {
...state,
@ -849,7 +808,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
case 'SET_GIT_CONFIG': {
const payload: {username: string; token: string; email: string} =
const payload =
action.payload
return {
...state,
@ -1138,7 +1097,7 @@ const addContextMenuItem = (
const removeContextMenuItem = (
state: BrowserState,
plugin
plugin: {name: string}
): {
registeredMenuItems: action[]
removedMenuItems: action[]

@ -1,7 +1,7 @@
import React, {useState, useEffect, useRef, useContext, SyntheticEvent, ChangeEvent, KeyboardEvent, MouseEvent} from 'react' // eslint-disable-line
import React, {useState, useEffect, useRef, useContext, ChangeEvent} from 'react' // eslint-disable-line
import {FormattedMessage, useIntl} from 'react-intl'
import {Dropdown} from 'react-bootstrap'
import {CustomIconsToggle, CustomMenu, CustomToggle, CustomTooltip, extractNameFromKey, extractParentFromKey} from '@remix-ui/helper'
import {CustomIconsToggle, CustomMenu, CustomToggle, extractNameFromKey, extractParentFromKey} from '@remix-ui/helper'
import {FileExplorer} from './components/file-explorer' // eslint-disable-line
import {FileSystemContext} from './contexts'
import './css/remix-ui-workspace.css'
@ -385,7 +385,6 @@ export function Workspace() {
// @ts-ignore
uupsRadioRef.current.checked = false
} else displayOzCustomRef.current.style.display = 'none'
// @ts-ignore
let displayName = TEMPLATE_NAMES[(workspaceCreateTemplateInput.current && workspaceCreateTemplateInput.current.value) || 'remixDefault']
displayName = global.plugin.getAvailableWorkspaceName(displayName)
@ -729,6 +728,11 @@ export function Workspace() {
{intl.formatMessage({id: 'filePanel.multiSigWallet'})}
</option>
</optgroup>
<optgroup style={{fontSize: 'medium'}} label="Circom ZKP">
<option style={{fontSize: 'small'}} value="semaphore">
{intl.formatMessage({id: 'filePanel.semaphore'})}
</option>
</optgroup>
</select>
<div id="ozcustomization" data-id="ozCustomization" ref={displayOzCustomRef} style={{display: 'none'}} className="mb-2">

@ -5,18 +5,7 @@ import { fileDecoration } from '@remix-ui/file-decorators'
import { RemixAppManager } from 'libs/remix-ui/plugin-manager/src/types'
import { ViewPlugin } from '@remixproject/engine-web'
export type action = {
name: string
type?: Array<'folder' | 'gist' | 'file' | 'workspace'>
path?: string[]
extension?: string[]
pattern?: string[]
id: string
multiselect: boolean
label: string
sticky?: boolean
group: number
}
export type action = { name: string, type?: Array<WorkspaceElement>, path?: string[], extension?: string[], pattern?: string[], id: string, multiselect: boolean, label: string, sticky?: boolean, group: number }
export interface JSONStandardInput {
language: 'Solidity'
settings?: any
@ -28,7 +17,7 @@ export interface JSONStandardInput {
}
}
export type MenuItems = action[]
export type WorkspaceTemplate = 'gist-template' | 'code-template' | 'remixDefault' | 'blank' | 'ozerc20' | 'zeroxErc20' | 'ozerc721' | 'playground'
export type WorkspaceTemplate = 'gist-template' | 'code-template' | 'remixDefault' | 'blank' | 'ozerc20' | 'zeroxErc20' | 'ozerc721' | 'playground' | 'semaphore'
export interface WorkspaceProps {
plugin: FilePanelType
}
@ -88,54 +77,54 @@ export interface FilePanelType extends ViewPlugin {
/* eslint-disable-next-line */
export interface FileExplorerProps {
name: string
menuItems?: string[]
contextMenuItems: MenuItems
removedContextMenuItems: MenuItems
files: { [x: string]: Record<string, FileType> }
workspaceState: WorkSpaceState
fileState: fileDecoration[]
expandPath: string[]
focusEdit: string
hideIconsMenu: React.Dispatch<React.SetStateAction<boolean>>
showIconsMenu: boolean
focusElement: { key: string; type: 'file' | 'folder' | 'gist' }[]
dispatchCreateNewFile: (path: string, rootDir: string) => Promise<void>
// eslint-disable-next-line no-undef
modal: (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => void
dispatchCreateNewFolder: (path: string, rootDir: string) => Promise<void>
readonly: boolean
toast: (toasterMsg: string) => void
dispatchDeletePath: (path: string[]) => Promise<void>
dispatchRenamePath: (oldPath: string, newPath: string) => Promise<void>
dispatchDownloadPath: (path: string) => Promise<void>
dispatchUploadFile: (target?: React.SyntheticEvent, targetFolder?: string) => Promise<void>
dispatchUploadFolder: (target?: React.SyntheticEvent, targetFolder?: string) => Promise<void>
dispatchCopyFile: (src: string, dest: string) => Promise<void>
dispatchCopyFolder: (src: string, dest: string) => Promise<void>
dispatchRunScript: (path: string) => Promise<void>
dispatchPublishToGist: (path?: string, type?: string) => Promise<void>
dispatchEmitContextMenuEvent: (cmd: customAction) => Promise<void>
dispatchHandleClickFile: (path: string, type: 'file' | 'folder' | 'gist') => Promise<void>
dispatchSetFocusElement: (elements: { key: string; type: 'file' | 'folder' | 'gist' }[]) => Promise<void>
dispatchFetchDirectory: (path: string) => Promise<void>
dispatchRemoveInputField: (path: string) => Promise<void>
dispatchAddInputField: (path: string, type: 'file' | 'folder') => Promise<void>
dispatchHandleExpandPath: (paths: string[]) => Promise<void>
dispatchMoveFile: (src: string, dest: string) => Promise<void>
dispatchMoveFolder: (src: string, dest: string) => Promise<void>
handlePasteClick: (dest: string, destType: string) => void
handleCopyClick: (path: string, type: 'folder' | 'gist' | 'file' | 'workspace') => void
addMenuItems: (items: MenuItems) => void
removeMenuItems: (items: MenuItems) => void
handleContextMenu: (pageX: number, pageY: number, path: string, content: string, type: string) => void
uploadFile: (target) => void
uploadFolder: (target) => void
getFocusedFolder: () => string
editModeOn: (path: string, type: string, isNew: boolean) => void
toGist: (path?: string, type?: string) => void
handleNewFileInput: (parentFolder?: string) => Promise<void>
handleNewFolderInput: (parentFolder?: string) => Promise<void>
name: string,
menuItems?: string[],
contextMenuItems: MenuItems,
removedContextMenuItems: MenuItems,
files: { [x: string]: Record<string, FileType> },
workspaceState: WorkSpaceState,
fileState: fileDecoration[],
expandPath: string[],
focusEdit: string,
hideIconsMenu: React.Dispatch<React.SetStateAction<boolean>>,
showIconsMenu: boolean,
focusElement: { key: string, type: WorkspaceElement }[],
dispatchCreateNewFile: (path: string, rootDir: string) => Promise<void>,
// eslint-disable-next-line no-undef
modal:(title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => void,
dispatchCreateNewFolder: (path: string, rootDir: string) => Promise<void>,
readonly: boolean,
toast: (toasterMsg: string) => void,
dispatchDeletePath: (path: string[]) => Promise<void>,
dispatchRenamePath: (oldPath: string, newPath: string) => Promise<void>,
dispatchDownloadPath: (path: string) => Promise<void>,
dispatchUploadFile: (target?: React.SyntheticEvent, targetFolder?: string) => Promise<void>,
dispatchUploadFolder: (target?: React.SyntheticEvent, targetFolder?: string) => Promise<void>,
dispatchCopyFile: (src: string, dest: string) => Promise<void>,
dispatchCopyFolder: (src: string, dest: string) => Promise<void>,
dispatchRunScript: (path: string) => Promise<void>,
dispatchPublishToGist: (path?: string, type?: string) => Promise<void>,
dispatchEmitContextMenuEvent: (cmd: customAction) => Promise<void>,
dispatchHandleClickFile: (path: string, type: WorkspaceElement) => Promise<void>,
dispatchSetFocusElement: (elements: { key: string, type: WorkspaceElement }[]) => Promise<void>,
dispatchFetchDirectory:(path: string) => Promise<void>,
dispatchRemoveInputField:(path: string) => Promise<void>,
dispatchAddInputField:(path: string, type: 'file' | 'folder') => Promise<void>,
dispatchHandleExpandPath: (paths: string[]) => Promise<void>,
dispatchMoveFile: (src: string, dest: string) => Promise<void>,
dispatchMoveFolder: (src: string, dest: string) => Promise<void>,
handlePasteClick: (dest: string, destType: string) => void
handleCopyClick: (path: string, type: WorkspaceElement) => void
addMenuItems: (items: MenuItems) => void
removeMenuItems: (items: MenuItems) => void
handleContextMenu: (pageX: number, pageY: number, path: string, content: string, type: string) => void
uploadFile: (target) => void
uploadFolder: (target) => void
getFocusedFolder: () => string
editModeOn: (path: string, type: string, isNew: boolean) => void
toGist: (path?: string, type?: string) => void
handleNewFileInput: (parentFolder?: string) => Promise<void>
handleNewFolderInput: (parentFolder?: string) => Promise<void>
}
type Placement = import('react-overlays/usePopper').Placement
export interface FileExplorerMenuProps {
@ -177,30 +166,30 @@ export interface FileExplorerContextMenuProps {
}
export interface WorkSpaceState {
ctrlKey: boolean
newFileName: string
actions: {
id: string
name: string
type?: Array<'folder' | 'gist' | 'file' | 'workspace'>
path?: string[]
extension?: string[]
pattern?: string[]
multiselect: boolean
label: string
group: number
}[]
focusContext: FileFocusContextType
focusEdit: {
element: string
type: string
isNew: boolean
lastEdit: string
}
mouseOverElement: string
showContextMenu: boolean
reservedKeywords: string[]
copyElement: CopyElementType[]
ctrlKey: boolean
newFileName: string
actions: {
id: string
name: string
type?: Array<WorkspaceElement>
path?: string[]
extension?: string[]
pattern?: string[]
multiselect: boolean
label: string,
group: number
}[]
focusContext: FileFocusContextType
focusEdit: {
element: string
type: string
isNew: boolean
lastEdit: string
}
mouseOverElement: string
showContextMenu: boolean
reservedKeywords: string[]
copyElement: CopyElementType[]
}
export type FileFocusContextType = {
@ -212,5 +201,107 @@ export type FileFocusContextType = {
export type CopyElementType = {
key: string
type: 'folder' | 'gist' | 'file' | 'workspace'
type: WorkspaceElement
}
export type FileTree = {
[x: string]: {
isDirectory: boolean
}
}
export interface ActionPayloadTypes {
SET_CURRENT_WORKSPACE: {
name: string
isGitRepo: boolean
branches?: {remote: string | undefined; name: string}[]
currentBranch?: string
},
SET_WORKSPACES: {
name: string
isGitRepo: boolean
branches?: {remote: string | undefined; name: string}[]
currentBranch?: string
}[],
SET_MODE: 'browser' | 'localhost',
FETCH_DIRECTORY_REQUEST: undefined | null,
FETCH_DIRECTORY_SUCCESS: { path: string; fileTree: FileTree },
FETCH_DIRECTORY_ERROR: string,
FETCH_WORKSPACE_DIRECTORY_REQUEST: undefined | null,
FETCH_WORKSPACE_DIRECTORY_SUCCESS: { path: string; fileTree: FileTree },
FETCH_WORKSPACE_DIRECTORY_ERROR: string,
DISPLAY_NOTIFICATION: {
title: string
message: string
actionOk: () => void
actionCancel: () => void
labelOk: string
labelCancel: string
},
HIDE_NOTIFICATION: undefined | null,
FILE_ADDED_SUCCESS: string,
FOLDER_ADDED_SUCCESS: {
path: string
folderPath: string
fileTree: FileTree
},
FILE_REMOVED_SUCCESS: string,
ROOT_FOLDER_CHANGED: string,
ADD_INPUT_FIELD: {
path: string
fileTree: FileTree
type: 'file' | 'folder'
},
REMOVE_INPUT_FIELD: { path: string; },
SET_READ_ONLY_MODE: boolean,
FILE_RENAMED_SUCCESS: {
path: string
oldPath: string
fileTree: FileTree
},
CREATE_WORKSPACE_REQUEST: undefined | null,
CREATE_WORKSPACE_SUCCESS: {
name: string
isGitRepo: boolean
branches?: { remote: string | undefined; name: string }[]
currentBranch?: string
},
CREATE_WORKSPACE_ERROR: string,
RENAME_WORKSPACE: { oldName: string; workspaceName: string },
DELETE_WORKSPACE: string,
DISPLAY_POPUP_MESSAGE: string,
HIDE_POPUP_MESSAGE: undefined | null,
SET_FOCUS_ELEMENT: {
key: string
type: WorkspaceElement
}[],
REMOVE_FOCUS_ELEMENT: string,
SET_CONTEXT_MENU_ITEM: action,
REMOVE_CONTEXT_MENU_ITEM: { name: string },
SET_EXPAND_PATH: string[],
LOAD_LOCALHOST_REQUEST: undefined | null,
LOAD_LOCALHOST_SUCCESS: undefined | null,
LOAD_LOCALHOST_ERROR: string,
CLONE_REPOSITORY_REQUEST: undefined | null,
CLONE_REPOSITORY_SUCCESS: undefined | null,
CLONE_REPOSITORY_FAILED: undefined | null,
FS_INITIALIZATION_COMPLETED: undefined | null,
SET_FILE_DECORATION_SUCCESS: fileDecoration[],
SET_CURRENT_WORKSPACE_BRANCHES: { remote: string | undefined; name: string }[],
SET_CURRENT_WORKSPACE_CURRENT_BRANCH: string,
SET_CURRENT_WORKSPACE_IS_GITREPO: boolean,
SET_GIT_CONFIG: {
username: string;
token: string;
email: string
}
}
export interface Action<T extends keyof ActionPayloadTypes> {
type: T,
payload: ActionPayloadTypes[T]
}
export type Actions = {[A in keyof ActionPayloadTypes]: Action<A>}[keyof ActionPayloadTypes]
export type WorkspaceElement = 'folder' | 'gist' | 'file' | 'workspace'

@ -81,5 +81,6 @@ export const TEMPLATE_NAMES = {
'ozerc1155': 'OpenZeppelin ERC1155',
'zeroxErc20': '0xProject ERC20',
'gnosisSafeMultisig': 'Gnosis Safe',
'playground': 'Playground'
'playground': 'Playground',
'semaphore': 'Semaphore'
}

@ -6,6 +6,7 @@ export { default as ozerc1155 } from './templates/ozerc1155'
export { default as zeroxErc20 } from './templates/zeroxErc20'
export { default as gnosisSafeMultisig } from './templates/gnosisSafeMultisig'
export { default as playground } from './templates/playground'
export { default as semaphore } from './templates/semaphore'
export { contractDeployerScripts } from './script-templates/contract-deployer'
export { etherscanScripts } from './script-templates/etherscan'

@ -23,6 +23,12 @@ export default async (opts) => {
// If no options is selected, opts.upgradeable will be undefined
// We do not show test file for upgradeable contract
// @ts-ignore
if (!opts || opts.upgradeable === undefined || !opts.upgradeable) filesObj['tests/MyToken_test.sol'] = (await import('raw-loader!./tests/MyToken_test.sol')).default
if (!opts || opts.upgradeable === undefined || !opts.upgradeable) {
// @ts-ignore
if (erc1155.defaults.mintable) filesObj['tests/MyToken_test.sol'] = (await import('raw-loader!./tests/MyToken_mintable_test.sol')).default
// @ts-ignore
else filesObj['tests/MyToken_test.sol'] = (await import('raw-loader!./tests/MyToken_test.sol')).default
}
return filesObj
}

@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "remix_tests.sol";
import "remix_accounts.sol";
import "../contracts/MyToken.sol";
contract MyTokenTest {
MyToken s;
function beforeAll () public {
address acc0 = TestsAccounts.getAccount(0);
// acc0 will be set as initial owner
s = new MyToken(acc0);
}
function testSetURI () public {
string memory uri = "https://testuri.io/token";
s.setURI(uri);
Assert.equal(s.uri(1), uri, "uri did not match");
}
}

@ -29,7 +29,6 @@ export default async (opts) => {
if (erc20.defaults.mintable) filesObj['tests/MyToken_test.sol'] = (await import('raw-loader!./tests/MyToken_mintable_test.sol')).default
// @ts-ignore
else filesObj['tests/MyToken_test.sol'] = (await import('raw-loader!./tests/MyToken_test.sol')).default
}
return filesObj
}

@ -7,14 +7,16 @@ import "../contracts/MyToken.sol";
contract MyTokenTest is MyToken {
address acc0;
address acc0 = TestsAccounts.getAccount(0);
address acc1;
address acc2;
address acc3;
address acc4;
// acc0 will be set as initial owner
constructor() MyToken(acc0) {}
function beforeAll() public {
acc0 = TestsAccounts.getAccount(0);
acc1 = TestsAccounts.getAccount(1);
acc2 = TestsAccounts.getAccount(2);
acc3 = TestsAccounts.getAccount(3);

@ -24,6 +24,11 @@ export default async (opts) => {
// If no options is selected, opts.upgradeable will be undefined
// We do not show test file for upgradeable contract
// @ts-ignore
if (!opts || opts.upgradeable === undefined || !opts.upgradeable) filesObj['tests/MyToken_test.sol'] = (await import('raw-loader!./tests/MyToken_test.sol')).default
if (!opts || opts.upgradeable === undefined || !opts.upgradeable) {
// @ts-ignore
if (erc721.defaults.mintable) filesObj['tests/MyToken_test.sol'] = (await import('raw-loader!./tests/MyToken_mintable_test.sol')).default
// @ts-ignore
else filesObj['tests/MyToken_test.sol'] = (await import('raw-loader!./tests/MyToken_test.sol')).default
}
return filesObj
}

@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "remix_tests.sol";
import "remix_accounts.sol";
import "../contracts/MyToken.sol";
contract MyTokenTest {
MyToken s;
function beforeAll () public {
address acc0 = TestsAccounts.getAccount(0);
// acc0 will be set as initial owner
s = new MyToken(acc0);
}
function testTokenNameAndSymbol () public {
Assert.equal(s.name(), "MyToken", "token name did not match");
Assert.equal(s.symbol(), "MTK", "token symbol did not match");
}
}

@ -0,0 +1,9 @@
REMIX CIRCOM WORKSPACE
Welcome to the Remix Circom Workspace. This workspace becomes available when you create a new workspace using the 'Circom' template.
Directory Structure
The workspace comprises two main directories:
circuits: Contains sample semaphore contracts. These can be compiled to generate a witness.
scripts: Provides a sample script designed for a trusted setup using snarkjs. This script also aids in generating Solidity code, which is essential for on-chain deployment.

@ -0,0 +1,90 @@
pragma circom 2.0.0;
include "circomlib/poseidon.circom";
include "./tree.circom";
template CalculateSecret() {
signal input identityNullifier;
signal input identityTrapdoor;
signal output out;
component poseidon = Poseidon(2);
poseidon.inputs[0] <== identityNullifier;
poseidon.inputs[1] <== identityTrapdoor;
out <== poseidon.out;
}
template CalculateIdentityCommitment() {
signal input secret;
signal output out;
component poseidon = Poseidon(1);
poseidon.inputs[0] <== secret;
out <== poseidon.out;
}
template CalculateNullifierHash() {
signal input externalNullifier;
signal input identityNullifier;
signal output out;
component poseidon = Poseidon(2);
poseidon.inputs[0] <== externalNullifier;
poseidon.inputs[1] <== identityNullifier;
out <== poseidon.out;
}
// credits to : https://github.com/semaphore-protocol/semaphore
// The current Semaphore smart contracts require nLevels <= 32 and nLevels >= 16.
template Semaphore(nLevels) {
signal input identityNullifier;
signal input identityTrapdoor;
signal input treePathIndices[nLevels];
signal input treeSiblings[nLevels];
signal input signalHash;
signal input externalNullifier;
signal output root;
signal output nullifierHash;
component calculateSecret = CalculateSecret();
calculateSecret.identityNullifier <== identityNullifier;
calculateSecret.identityTrapdoor <== identityTrapdoor;
signal secret;
secret <== calculateSecret.out;
component calculateIdentityCommitment = CalculateIdentityCommitment();
calculateIdentityCommitment.secret <== secret;
component calculateNullifierHash = CalculateNullifierHash();
calculateNullifierHash.externalNullifier <== externalNullifier;
calculateNullifierHash.identityNullifier <== identityNullifier;
component inclusionProof = MerkleTreeInclusionProof(nLevels);
inclusionProof.leaf <== calculateIdentityCommitment.out;
for (var i = 0; i < nLevels; i++) {
inclusionProof.siblings[i] <== treeSiblings[i];
inclusionProof.pathIndices[i] <== treePathIndices[i];
}
root <== inclusionProof.root;
// Dummy square to prevent tampering signalHash.
signal signalHashSquared;
signalHashSquared <== signalHash * signalHash;
nullifierHash <== calculateNullifierHash.out;
}
component main {public [signalHash, externalNullifier]} = Semaphore(20);

@ -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,40 @@
pragma circom 2.0.0;
include "circomlib/poseidon.circom";
include "circomlib/mux1.circom";
template MerkleTreeInclusionProof(nLevels) {
signal input leaf;
signal input pathIndices[nLevels];
signal input siblings[nLevels];
signal output root;
component poseidons[nLevels];
component mux[nLevels];
signal hashes[nLevels + 1];
hashes[0] <== leaf;
for (var i = 0; i < nLevels; i++) {
pathIndices[i] * (1 - pathIndices[i]) === 0;
poseidons[i] = Poseidon(2);
mux[i] = MultiMux1(2);
mux[i].c[0][0] <== hashes[i];
mux[i].c[0][1] <== siblings[i];
mux[i].c[1][0] <== siblings[i];
mux[i].c[1][1] <== hashes[i];
mux[i].s <== pathIndices[i];
poseidons[i].inputs[0] <== mux[i].out[0];
poseidons[i].inputs[1] <== mux[i].out[1];
hashes[i + 1] <== poseidons[i].out;
}
root <== hashes[nLevels];
}

@ -0,0 +1,18 @@
export default async () => {
return {
// @ts-ignore
'circuits/semaphore.circom': (await import('raw-loader!./circuits/semaphore.circom')).default,
// @ts-ignore
'circuits/simple.circom': (await import('!!raw-loader!./circuits/simple.circom')).default,
// @ts-ignore
'circuits/tree.circom': (await import('!!raw-loader!./circuits/tree.circom')).default,
// @ts-ignore
'scripts/run_setup.ts': (await import('!!raw-loader!./scripts/run_setup.ts')).default,
// @ts-ignore
'scripts/run_verification.ts': (await import('!!raw-loader!./scripts/run_verification.ts')).default,
// @ts-ignore
'templates/groth16_verifier.sol.ejs': (await import('!!raw-loader!./templates/groth16_verifier.sol.ejs')).default,
// @ts-ignore
'README.txt': (await import('raw-loader!./README.txt')).default
}
}

@ -0,0 +1,72 @@
import { ethers, BigNumber } from 'ethers'
// eslint-disable-next-line @typescript-eslint/no-var-requires
const snarkjs = require('snarkjs');
const logger = {
info: (...args) => console.log(...args),
debug: (...args) => console.log(...args)
};
/**
* Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
* @param message The message to be hashed.
* @returns The message digest.
*/
function hash(message: any): bigint {
message = BigNumber.from(message).toTwos(256).toHexString()
message = ethers.utils.zeroPad(message, 32)
return BigInt(ethers.utils.keccak256(message)) >> BigInt(8)
}
(async () => {
try {
// @ts-ignore
await remix.call('circuit-compiler', 'generateR1cs', 'circuits/semaphore.circom');
const ptau_final = "https://ipfs-cluster.ethdevops.io/ipfs/QmTiT4eiYz5KF7gQrDsgfCSTRv3wBPYJ4bRN1MmTRshpnW";
// @ts-ignore
const r1csBuffer = await remix.call('fileManager', 'readFile', 'circuits/.bin/semaphore.r1cs', true);
// @ts-ignore
const r1cs = new Uint8Array(r1csBuffer);
const zkey_0 = { type: "mem" };
const zkey_1 = { type: "mem" };
const zkey_final = { type: "mem" };
console.log('newZkey')
await snarkjs.zKey.newZKey(r1cs, ptau_final, zkey_0);
console.log('contribute')
await snarkjs.zKey.contribute(zkey_0, zkey_1, "p2_C1", "pa_Entropy1");
console.log('beacon')
await snarkjs.zKey.beacon(zkey_1, zkey_final, "B3", "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", 10);
console.log('verifyFromR1cs')
const verifyFromR1csResult = await snarkjs.zKey.verifyFromR1cs(r1cs, ptau_final, zkey_final);
console.assert(verifyFromR1csResult);
console.log('verifyFromInit')
const verifyFromInit = await snarkjs.zKey.verifyFromInit(zkey_0, ptau_final, zkey_final);
console.assert(verifyFromInit);
console.log('exportVerificationKey')
const vKey = await snarkjs.zKey.exportVerificationKey(zkey_final)
await remix.call('fileManager', 'writeFile', './zk/build/verification_key.json', JSON.stringify(vKey))
const templates = {
groth16: await remix.call('fileManager', 'readFile', 'templates/groth16_verifier.sol.ejs')
}
const solidityContract = await snarkjs.zKey.exportSolidityVerifier(zkey_final, templates)
await remix.call('fileManager', 'writeFile', './zk/build/zk_verifier.sol', solidityContract)
console.log('buffer', (zkey_final as any).data.length)
await remix.call('fileManager', 'writeFile', './zk/build/zk_setup.txt', JSON.stringify(Array.from(((zkey_final as any).data))))
console.log('setup done.')
} catch (e) {
console.error(e.message)
}
})()

@ -0,0 +1,102 @@
import { ethers, BigNumber } from 'ethers'
import { IncrementalMerkleTree } from "@zk-kit/incremental-merkle-tree"
import { poseidon } from "circomlibjs" // v0.0.8
// eslint-disable-next-line @typescript-eslint/no-var-requires
const snarkjs = require('snarkjs');
const logger = {
info: (...args) => console.log(...args),
debug: (...args) => console.log(...args),
error: (...args) => console.error(...args),
}
/**
* Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
* @param message The message to be hashed.
* @returns The message digest.
*/
function hash(message: any): bigint {
message = BigNumber.from(message).toTwos(256).toHexString()
message = ethers.utils.zeroPad(message, 32)
return BigInt(ethers.utils.keccak256(message)) >> BigInt(8)
}
(async () => {
try {
// @ts-ignore
const r1csBuffer = await remix.call('fileManager', 'readFile', 'circuits/.bin/semaphore.r1cs', true);
// @ts-ignore
const r1cs = new Uint8Array(r1csBuffer);
// @ts-ignore
const wasmBuffer = await remix.call('fileManager', 'readFile', 'circuits/.bin/semaphore.wasm', true);
// @ts-ignore
const wasm = new Uint8Array(wasmBuffer);
const zkey_final = {
type: "mem",
data: new Uint8Array(JSON.parse(await remix.call('fileManager', 'readFile', './zk/build/zk_setup.txt')))
}
const wtns = { type: "mem" };
const vKey = JSON.parse(await remix.call('fileManager', 'readFile', './zk/build/verification_key.json'))
// build list of identity commitments
const secrets = []
const identityCommitments = []
for (let k = 0; k < 2; k++) {
const identityTrapdoor = BigInt(ethers.utils.hexlify(ethers.utils.randomBytes(32)))
const identityNullifier = BigInt(ethers.utils.hexlify(ethers.utils.randomBytes(32)))
secrets.push({identityTrapdoor, identityNullifier})
const secret = poseidon([identityNullifier, identityTrapdoor])
const identityCommitment = poseidon([secret])
identityCommitments.push(identityCommitment)
}
//console.log('incremental tree', identityCommitments.map((x) => x.toString()))
let tree
try {
tree = new IncrementalMerkleTree(poseidon, 20, BigInt(0), 2, identityCommitments) // Binary tree.
} catch (e) {
console.error(e.message)
return
}
const index = tree.indexOf(identityCommitments[0])
console.log(index.toString())
const proof1 = tree.createProof(0)
console.log('prepare signals for id ', identityCommitments[0].toString(), tree.indexOf(identityCommitments[0]), proof1.siblings.map((x)=> x.toString()))
const signals = {
identityTrapdoor: secrets[0].identityTrapdoor,
identityNullifier: secrets[0].identityNullifier,
treePathIndices: proof1.pathIndices,
treeSiblings: proof1.siblings,
externalNullifier: hash(42),
signalHash: hash(ethers.utils.formatBytes32String("Hello World"))
}
console.log('calculate')
await snarkjs.wtns.calculate(signals, wasm, wtns);
console.log('check')
await snarkjs.wtns.check(r1cs, wtns, logger);
console.log('prove')
const { proof, publicSignals } = await snarkjs.groth16.prove(zkey_final, wtns);
const verified = await snarkjs.groth16.verify(vKey, publicSignals, proof, logger);
console.log('zk proof validity', verified);
proof1.root.toString() === publicSignals[0] ? console.log('merkle proof valid') : console.log('merkle proof invalid')
} catch (e) {
console.error(e.message)
}
})()

@ -0,0 +1,165 @@
// SPDX-License-Identifier: GPL-3.0
/*
Copyright 2021 0KIMS association.
This file is generated with [snarkJS](https://github.com/iden3/snarkjs).
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity >=0.7.0 <0.9.0;
contract Groth16Verifier {
// Scalar field size
uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
// Base field size
uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// Verification Key data
uint256 constant alphax = <%= vk_alpha_1[0] %>;
uint256 constant alphay = <%= vk_alpha_1[1] %>;
uint256 constant betax1 = <%= vk_beta_2[0][1] %>;
uint256 constant betax2 = <%= vk_beta_2[0][0] %>;
uint256 constant betay1 = <%= vk_beta_2[1][1] %>;
uint256 constant betay2 = <%= vk_beta_2[1][0] %>;
uint256 constant gammax1 = <%= vk_gamma_2[0][1] %>;
uint256 constant gammax2 = <%= vk_gamma_2[0][0] %>;
uint256 constant gammay1 = <%= vk_gamma_2[1][1] %>;
uint256 constant gammay2 = <%= vk_gamma_2[1][0] %>;
uint256 constant deltax1 = <%= vk_delta_2[0][1] %>;
uint256 constant deltax2 = <%= vk_delta_2[0][0] %>;
uint256 constant deltay1 = <%= vk_delta_2[1][1] %>;
uint256 constant deltay2 = <%= vk_delta_2[1][0] %>;
<% for (let i=0; i<IC.length; i++) { %>
uint256 constant IC<%=i%>x = <%=IC[i][0]%>;
uint256 constant IC<%=i%>y = <%=IC[i][1]%>;
<% } %>
// Memory data
uint16 constant pVk = 0;
uint16 constant pPairing = 128;
uint16 constant pLastMem = 896;
function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[<%=IC.length-1%>] calldata _pubSignals) public view returns (bool) {
assembly {
function checkField(v) {
if iszero(lt(v, q)) {
mstore(0, 0)
return(0, 0x20)
}
}
// G1 function to multiply a G1 value(x,y) to value in an address
function g1_mulAccC(pR, x, y, s) {
let success
let mIn := mload(0x40)
mstore(mIn, x)
mstore(add(mIn, 32), y)
mstore(add(mIn, 64), s)
success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
if iszero(success) {
mstore(0, 0)
return(0, 0x20)
}
mstore(add(mIn, 64), mload(pR))
mstore(add(mIn, 96), mload(add(pR, 32)))
success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
if iszero(success) {
mstore(0, 0)
return(0, 0x20)
}
}
function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
let _pPairing := add(pMem, pPairing)
let _pVk := add(pMem, pVk)
mstore(_pVk, IC0x)
mstore(add(_pVk, 32), IC0y)
// Compute the linear combination vk_x
<% for (let i = 1; i <= nPublic; i++) { %>
g1_mulAccC(_pVk, IC<%=i%>x, IC<%=i%>y, calldataload(add(pubSignals, <%=(i-1)*32%>)))
<% } %>
// -A
mstore(_pPairing, calldataload(pA))
mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))
// B
mstore(add(_pPairing, 64), calldataload(pB))
mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
mstore(add(_pPairing, 160), calldataload(add(pB, 96)))
// alpha1
mstore(add(_pPairing, 192), alphax)
mstore(add(_pPairing, 224), alphay)
// beta2
mstore(add(_pPairing, 256), betax1)
mstore(add(_pPairing, 288), betax2)
mstore(add(_pPairing, 320), betay1)
mstore(add(_pPairing, 352), betay2)
// vk_x
mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))
// gamma2
mstore(add(_pPairing, 448), gammax1)
mstore(add(_pPairing, 480), gammax2)
mstore(add(_pPairing, 512), gammay1)
mstore(add(_pPairing, 544), gammay2)
// C
mstore(add(_pPairing, 576), calldataload(pC))
mstore(add(_pPairing, 608), calldataload(add(pC, 32)))
// delta2
mstore(add(_pPairing, 640), deltax1)
mstore(add(_pPairing, 672), deltax2)
mstore(add(_pPairing, 704), deltay1)
mstore(add(_pPairing, 736), deltay2)
let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)
isOk := and(success, mload(_pPairing))
}
let pMem := mload(0x40)
mstore(0x40, add(pMem, pLastMem))
// Validate that all evaluations ∈ F
<% for (let i=0; i<IC.length; i++) { %>
checkField(calldataload(add(_pubSignals, <%=i*32%>)))
<% } %>
// Validate all evaluations
let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)
mstore(0, isValid)
return(0, 0x20)
}
}
}

@ -150,7 +150,7 @@
"brace": "^0.8.0",
"change-case": "^4.1.1",
"chokidar": "^2.1.8",
"circom_wasm": "^0.0.2",
"circom_wasm": "^0.1.0",
"color-support": "^1.1.3",
"commander": "^9.4.1",
"core-js": "^3.6.5",
@ -202,6 +202,7 @@
"remark-gfm": "^3.0.1",
"rss-parser": "^3.12.0",
"signale": "^1.4.0",
"snarkjs": "^0.7.0",
"sol2uml": "^2.4.3",
"string-similarity": "^4.0.4",
"svg2pdf.js": "^2.2.1",

@ -2616,6 +2616,19 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@iden3/bigarray@0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@iden3/bigarray/-/bigarray-0.0.2.tgz#6fc4ba5be18daf8a26ee393f2fb62b80d98c05e9"
integrity sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g==
"@iden3/binfileutils@0.0.11":
version "0.0.11"
resolved "https://registry.yarnpkg.com/@iden3/binfileutils/-/binfileutils-0.0.11.tgz#9ffbbcc1279f2b2182bb6dcff4eee8a5b2167911"
integrity sha512-LylnJoZ0CTdgErnKY8OxohvW4K+p6UHD3sxt+3P9AmMyBQjYR4IpoqoYZZ+9aMj89cmCQ21UvdhndAx04er3NA==
dependencies:
fastfile "0.0.20"
ffjavascript "^0.2.48"
"@isomorphic-git/idb-keyval@3.3.2":
version "3.3.2"
resolved "https://registry.yarnpkg.com/@isomorphic-git/idb-keyval/-/idb-keyval-3.3.2.tgz#c0509a6c5987d8a62efb3e47f2815bcc5eda2489"
@ -7660,7 +7673,7 @@ axobject-query@^2.2.0:
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==
b4a@^1.6.4:
b4a@^1.0.1, b4a@^1.6.4:
version "1.6.4"
resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9"
integrity sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==
@ -8432,6 +8445,17 @@ before-after-hook@^2.0.0:
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e"
integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==
bfj@^7.0.2:
version "7.1.0"
resolved "https://registry.yarnpkg.com/bfj/-/bfj-7.1.0.tgz#c5177d522103f9040e1b12980fe8c38cf41d3f8b"
integrity sha512-I6MMLkn+anzNdCUp9hMRyui1HaNEUCco50lxbvNS4+EyXg8lN3nJ48PjPWtbH8UVS9CuMoaKE9U2V3l29DaRQw==
dependencies:
bluebird "^3.7.2"
check-types "^11.2.3"
hoopy "^0.1.4"
jsonpath "^1.1.1"
tryer "^1.0.1"
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
@ -8497,6 +8521,14 @@ bl@^4.0.0, bl@^4.0.3, bl@^4.1.0:
inherits "^2.0.4"
readable-stream "^3.4.0"
blake2b-wasm@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz#9115649111edbbd87eb24ce7c04b427e4e2be5be"
integrity sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==
dependencies:
b4a "^1.0.1"
nanoassert "^2.0.0"
blakejs@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.1.tgz#bf313053978b2cd4c444a48795710be05c785702"
@ -8521,7 +8553,7 @@ block-stream@*:
dependencies:
inherits "~2.0.0"
bluebird@^3.0.5, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5:
bluebird@^3.0.5, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5, bluebird@^3.7.2:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
@ -9525,6 +9557,11 @@ check-error@1.0.2, check-error@^1.0.2:
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==
check-types@^11.2.3:
version "11.2.3"
resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.3.tgz#1ffdf68faae4e941fce252840b1787b8edc93b71"
integrity sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==
cheerio-select@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4"
@ -9683,10 +9720,17 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
inherits "^2.0.1"
safe-buffer "^5.0.1"
circom_wasm@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/circom_wasm/-/circom_wasm-0.0.2.tgz#9d24866b8289a5778999270823a4cb06e64145b5"
integrity sha512-SCMP6cxHHL7MLedDrTl+nGYyE6+kE5GepbxtZm65GlR0wUMD9eNOD1shwScWaDnmBOZTrImmNeTYZA5DWCmIww==
circom_runtime@0.1.22:
version "0.1.22"
resolved "https://registry.yarnpkg.com/circom_runtime/-/circom_runtime-0.1.22.tgz#f957c47662cdd03cd3fb76979c434c719a366373"
integrity sha512-V/XYZWBhbZY8SotkaGH4FbiDYAZ8a1Md++MBiKPDOuWS/NIJB+Q+XIiTC8zKMgoDaa9cd2OiTvsC9J6te7twNg==
dependencies:
ffjavascript "0.2.57"
circom_wasm@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/circom_wasm/-/circom_wasm-0.1.0.tgz#dda76c7ae9046ea6f1e1cd3754c017ad753bd5c1"
integrity sha512-F7ihfVGjfSz+01yFXLHjKocQFm8j9KBageqMw5+olFWB6+7CXHLjnUaFuU6u+7T0FsL7+JuP18jdcAVQEXoQgw==
circular-json@^0.3.0:
version "0.3.3"
@ -11250,7 +11294,7 @@ deep-extend@~0.4.0:
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253"
integrity sha1-7+QRPQgIX05vlod1mBD4B0aeIlM=
deep-is@^0.1.3:
deep-is@^0.1.3, deep-is@~0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
@ -11839,6 +11883,13 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
ejs@^3.1.6:
version "3.1.9"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361"
integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==
dependencies:
jake "^10.8.5"
ejs@^3.1.7, ejs@^3.1.8:
version "3.1.8"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b"
@ -12248,6 +12299,18 @@ escape-string-regexp@^5.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
escodegen@^1.8.1:
version "1.14.3"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==
dependencies:
esprima "^4.0.1"
estraverse "^4.2.0"
esutils "^2.0.2"
optionator "^0.8.1"
optionalDependencies:
source-map "~0.6.1"
escodegen@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17"
@ -12476,6 +12539,11 @@ espree@^9.4.0:
acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.3.0"
esprima@1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.2.tgz#76a0fd66fcfe154fd292667dc264019750b1657b"
integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==
esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
@ -12495,7 +12563,7 @@ esrecurse@^4.3.0:
dependencies:
estraverse "^5.2.0"
estraverse@^4.1.1:
estraverse@^4.1.1, estraverse@^4.2.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
@ -13133,7 +13201,7 @@ fast-levenshtein@^1.0.0:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz#e6a754cc8f15e58987aa9cbd27af66fd6f4e5af9"
integrity sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=
fast-levenshtein@^2.0.6:
fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
@ -13163,6 +13231,11 @@ fastest-levenshtein@^1.0.12:
resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
fastfile@0.0.20:
version "0.0.20"
resolved "https://registry.yarnpkg.com/fastfile/-/fastfile-0.0.20.tgz#794a143d58cfda2e24c298e5ef619c748c8a1879"
integrity sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==
fastq@^1.6.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
@ -13226,6 +13299,33 @@ fetch-blob@^2.1.1, fetch-blob@^2.1.2:
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-2.1.2.tgz#a7805db1361bd44c1ef62bb57fb5fe8ea173ef3c"
integrity sha512-YKqtUDwqLyfyMnmbw8XD6Q8j9i/HggKtPEI+pZ1+8bvheBu78biSmNaXWusx1TauGqtUUGx/cBb1mKdq2rLYow==
ffjavascript@0.2.57:
version "0.2.57"
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.57.tgz#ba1be96015b2688192e49f2f4de2cc5150fd8594"
integrity sha512-V+vxZ/zPNcthrWmqfe/1YGgqdkTamJeXiED0tsk7B84g40DKlrTdx47IqZuiygqAVG6zMw4qYuvXftIJWsmfKQ==
dependencies:
wasmbuilder "0.0.16"
wasmcurves "0.2.0"
web-worker "^1.2.0"
ffjavascript@0.2.59:
version "0.2.59"
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.59.tgz#b2f836082587fab333dfb181b909a188f80036f3"
integrity sha512-QssOEUv+wilz9Sg7Zaj6KWAm7QceOAEsFuEBTltUsDo1cjn11rA/LGYvzFBPbzNfxRlZxwgJ7uxpCQcdDlrNfw==
dependencies:
wasmbuilder "0.0.16"
wasmcurves "0.2.1"
web-worker "^1.2.0"
ffjavascript@^0.2.48:
version "0.2.60"
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.60.tgz#4d8ae613d6bf4e98b3cc29ba10c626f5853854cf"
integrity sha512-T/9bnEL5xAZRDbQoEMf+pM9nrhK+C3JyZNmqiWub26EQorW7Jt+jR54gpqDhceA4Nj0YctPQwYnl8xa52/A26A==
dependencies:
wasmbuilder "0.0.16"
wasmcurves "0.2.2"
web-worker "^1.2.0"
fflate@^0.4.8:
version "0.4.8"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae"
@ -14883,6 +14983,11 @@ homedir-polyfill@^1.0.1:
dependencies:
parse-passwd "^1.0.0"
hoopy@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==
hosted-git-info@^2.1.4, hosted-git-info@^2.7.1:
version "2.8.9"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
@ -17196,6 +17301,15 @@ jsonparse@^1.2.0:
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.0.tgz#85fc245b1d9259acc6941960b905adf64e7de0e8"
integrity sha1-hfwkWx2SWazGlBlguQWt9k594Og=
jsonpath@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/jsonpath/-/jsonpath-1.1.1.tgz#0ca1ed8fb65bb3309248cc9d5466d12d5b0b9901"
integrity sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==
dependencies:
esprima "1.2.2"
static-eval "2.0.2"
underscore "1.12.1"
jspdf@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/jspdf/-/jspdf-2.5.1.tgz#00c85250abf5447a05f3b32ab9935ab4a56592cc"
@ -17537,6 +17651,14 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"
levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==
dependencies:
prelude-ls "~1.1.2"
type-check "~0.3.2"
license-webpack-plugin@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz#1e18442ed20b754b82f1adeff42249b81d11aec6"
@ -18033,6 +18155,11 @@ logform@^2.2.0:
safe-stable-stringify "^1.1.0"
triple-beam "^1.3.0"
logplease@^1.2.15:
version "1.2.15"
resolved "https://registry.yarnpkg.com/logplease/-/logplease-1.2.15.tgz#3da442e93751a5992cc19010a826b08d0293c48a"
integrity sha512-jLlHnlsPSJjpwUfcNyUxXCl33AYg2cHhIf9QhGL2T4iPT0XPB+xP1LRKFPgIg1M/sg9kAJvy94w9CzBNrfnstA==
longest-streak@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4"
@ -19574,6 +19701,11 @@ nanoassert@^1.1.0:
resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-1.1.0.tgz#4f3152e09540fde28c76f44b19bbcd1d5a42478d"
integrity sha1-TzFS4JVA/eKMdvRLGbvNHVpCR40=
nanoassert@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-2.0.0.tgz#a05f86de6c7a51618038a620f88878ed1e490c09"
integrity sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==
nanobench@^2.1.0, nanobench@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/nanobench/-/nanobench-2.1.1.tgz#c2f23fcce116d50b4998b1954ba114674c137269"
@ -20767,6 +20899,18 @@ optimist@^0.6.1:
minimist "~0.0.1"
wordwrap "~0.0.2"
optionator@^0.8.1:
version "0.8.3"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
dependencies:
deep-is "~0.1.3"
fast-levenshtein "~2.0.6"
levn "~0.3.0"
prelude-ls "~1.1.2"
type-check "~0.3.2"
word-wrap "~1.2.3"
optionator@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
@ -21988,6 +22132,11 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
prepend-http@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@ -22443,6 +22592,16 @@ quick-lru@^5.1.1:
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
r1csfile@0.0.45:
version "0.0.45"
resolved "https://registry.yarnpkg.com/r1csfile/-/r1csfile-0.0.45.tgz#59d59a33f8b5280017fc00ee691d003a3d705fe0"
integrity sha512-YKIp4D441aZ6OoI9y+bfAyb2j4Cl+OFq/iiX6pPWDrL4ZO968h0dq0w07i65edvrTt7/G43mTnl0qEuLXyp/Yw==
dependencies:
"@iden3/bigarray" "0.0.2"
"@iden3/binfileutils" "0.0.11"
fastfile "0.0.20"
ffjavascript "0.2.57"
raf-schd@^4.0.2:
version "4.0.3"
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
@ -24446,6 +24605,22 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
snarkjs@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/snarkjs/-/snarkjs-0.7.0.tgz#9b4d193a0535c1903e45f1508aa7ad74cd130844"
integrity sha512-Vu5W+0Va6X1xvlCllpZ2r3/S7MafnL6IrAv09lk/F+VNDHuHEHx3xopR9Kr70p2KpbBBJ/HB9VCDZWism8WGlA==
dependencies:
"@iden3/binfileutils" "0.0.11"
bfj "^7.0.2"
blake2b-wasm "^2.4.0"
circom_runtime "0.1.22"
ejs "^3.1.6"
fastfile "0.0.20"
ffjavascript "0.2.59"
js-sha3 "^0.8.0"
logplease "^1.2.15"
r1csfile "0.0.45"
sntp@1.x.x:
version "1.0.9"
resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
@ -24868,6 +25043,13 @@ state-local@^1.0.6:
resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5"
integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==
static-eval@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.2.tgz#2d1759306b1befa688938454c546b7871f806a42"
integrity sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==
dependencies:
escodegen "^1.8.1"
static-extend@^0.1.1, static-extend@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
@ -25997,6 +26179,11 @@ truncate-utf8-bytes@^1.0.0:
dependencies:
utf8-byte-length "^1.0.1"
tryer@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
ts-loader@^9.2.6:
version "9.2.6"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.2.6.tgz#9937c4dd0a1e3dbbb5e433f8102a6601c6615d74"
@ -26166,6 +26353,13 @@ type-check@^0.4.0, type-check@~0.4.0:
dependencies:
prelude-ls "^1.2.1"
type-check@~0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==
dependencies:
prelude-ls "~1.1.2"
type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5:
version "4.0.8"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
@ -26418,6 +26612,11 @@ undefsafe@^2.0.5:
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
underscore@1.12.1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e"
integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==
undertaker-registry@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/undertaker-registry/-/undertaker-registry-1.0.1.tgz#5e4bda308e4a8a2ae584f9b9a4359a499825cc50"
@ -27072,6 +27271,32 @@ warning@^4.0.0, warning@^4.0.3:
dependencies:
loose-envify "^1.0.0"
wasmbuilder@0.0.16:
version "0.0.16"
resolved "https://registry.yarnpkg.com/wasmbuilder/-/wasmbuilder-0.0.16.tgz#f34c1f2c047d2f6e1065cbfec5603988f16d8549"
integrity sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA==
wasmcurves@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.2.0.tgz#ccfc5a7d3778b6e0768b82a9336c80054f9bc0cf"
integrity sha512-3e2rbxdujOwaod657gxgmdhZNn+i1qKdHO3Y/bK+8E7bV8ttV/fu5FO4/WLBACF375cK0QDLOP+65Na63qYuWA==
dependencies:
wasmbuilder "0.0.16"
wasmcurves@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.2.1.tgz#416d15432a9c6a7b79ef6000eab1e8e7302624ad"
integrity sha512-9ciO7bUE5bgpbOcdK7IO3enrSVIKHwrQmPibok4GLJWaCA7Wyqc9PRYnu5HbiFv9NDFNqVKPtU5R6Is5KujBLg==
dependencies:
wasmbuilder "0.0.16"
wasmcurves@0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.2.2.tgz#ca444f6a6f6e2a5cbe6629d98ff478a62b4ccb2b"
integrity sha512-JRY908NkmKjFl4ytnTu5ED6AwPD+8VJ9oc94kdq7h5bIwbj0L4TDJ69mG+2aLs2SoCmGfqIesMWTEJjtYsoQXQ==
dependencies:
wasmbuilder "0.0.16"
watchify@^3.9.0:
version "3.11.1"
resolved "https://registry.yarnpkg.com/watchify/-/watchify-3.11.1.tgz#8e4665871fff1ef64c0430d1a2c9d084d9721881"
@ -27128,6 +27353,11 @@ web-streams-polyfill@^3.1.0:
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz#a6b74026b38e4885869fb5c589e90b95ccfc7965"
integrity sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==
web-worker@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.2.0.tgz#5d85a04a7fbc1e7db58f66595d7a3ac7c9c180da"
integrity sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==
web3-core@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-4.3.0.tgz#96c5e8f7ec92ea573f388785548bf31c4089d508"
@ -27670,6 +27900,11 @@ word-wrap@^1.2.3:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
word-wrap@~1.2.3:
version "1.2.5"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
wordwrap@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"

Loading…
Cancel
Save