Merge pull request #4164 from ethereum/semaphore-template

Semaphore template
pull/4129/head
David Disu 1 year ago committed by GitHub
commit 135b5dad44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      apps/remix-ide/src/app/tabs/locales/en/filePanel.json
  2. 6
      apps/remix-ide/src/remixAppManager.js
  3. 10
      libs/remix-ui/workspace/src/lib/actions/events.ts
  4. 15
      libs/remix-ui/workspace/src/lib/actions/index.ts
  5. 118
      libs/remix-ui/workspace/src/lib/actions/payload.ts
  6. 23
      libs/remix-ui/workspace/src/lib/actions/workspace.ts
  7. 4
      libs/remix-ui/workspace/src/lib/components/file-explorer.tsx
  8. 4
      libs/remix-ui/workspace/src/lib/components/file-render.tsx
  9. 97
      libs/remix-ui/workspace/src/lib/reducers/workspace.ts
  10. 10
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  11. 120
      libs/remix-ui/workspace/src/lib/types/index.ts
  12. 3
      libs/remix-ui/workspace/src/lib/utils/constants.ts
  13. 1
      libs/remix-ws-templates/src/index.ts
  14. 9
      libs/remix-ws-templates/src/templates/semaphore/README.txt
  15. 90
      libs/remix-ws-templates/src/templates/semaphore/circuits/semaphore.circom
  16. 11
      libs/remix-ws-templates/src/templates/semaphore/circuits/simple.circom
  17. 40
      libs/remix-ws-templates/src/templates/semaphore/circuits/tree.circom
  18. 18
      libs/remix-ws-templates/src/templates/semaphore/index.ts
  19. 72
      libs/remix-ws-templates/src/templates/semaphore/scripts/run_setup.ts
  20. 102
      libs/remix-ws-templates/src/templates/semaphore/scripts/run_verification.ts
  21. 165
      libs/remix-ws-templates/src/templates/semaphore/templates/groth16_verifier.sol.ejs

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

@ -74,8 +74,7 @@ const requiredModules = [
'compilationDetails', 'compilationDetails',
'contractflattener', 'contractflattener',
'solidity-script', 'solidity-script',
'openaigpt', 'openaigpt'
'circuit-compiler'
] ]
// dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd)
@ -114,7 +113,8 @@ export function isNative(name) {
'injected-ephemery-testnet-provider', 'injected-ephemery-testnet-provider',
'injected', 'injected',
'doc-gen', 'doc-gen',
'doc-viewer' 'doc-viewer',
'circuit-compiler'
] ]
return nativePlugins.includes(name) || requiredModules.includes(name) return nativePlugins.includes(name) || requiredModules.includes(name)
} }

@ -1,7 +1,7 @@
import { fileDecoration } from '@remix-ui/file-decorators' import { fileDecoration } from '@remix-ui/file-decorators'
import { extractParentFromKey } from '@remix-ui/helper' import { extractParentFromKey } from '@remix-ui/helper'
import React from 'react' import React from 'react'
import { action, WorkspaceTemplate } from '../types' import { action, FileTree, WorkspaceTemplate } from '../types'
import { ROOT_PATH } from '../utils/constants' 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 { 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' import { addInputField, createWorkspace, deleteWorkspace, fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile } from './workspace'
@ -173,8 +173,8 @@ const folderAdded = async (folderPath: string) => {
const provider = plugin.fileManager.currentFileProvider() const provider = plugin.fileManager.currentFileProvider()
const path = extractParentFromKey(folderPath) || ROOT_PATH const path = extractParentFromKey(folderPath) || ROOT_PATH
const promise = new Promise((resolve) => { const promise: Promise<FileTree> = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree) => { provider.resolveDirectory(path, (error, fileTree: FileTree) => {
if (error) console.error(error) if (error) console.error(error)
resolve(fileTree) resolve(fileTree)
}) })
@ -196,8 +196,8 @@ const fileRemoved = async (removePath: string) => {
const fileRenamed = async (oldPath: string) => { const fileRenamed = async (oldPath: string) => {
const provider = plugin.fileManager.currentFileProvider() const provider = plugin.fileManager.currentFileProvider()
const path = extractParentFromKey(oldPath) || ROOT_PATH const path = extractParentFromKey(oldPath) || ROOT_PATH
const promise = new Promise((resolve) => { const promise: Promise<FileTree> = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree) => { provider.resolveDirectory(path, (error, fileTree: FileTree) => {
if (error) console.error(error) if (error) console.error(error)
resolve(fileTree) resolve(fileTree)

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

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

@ -5,7 +5,7 @@ import axios, { AxiosResponse } from 'axios'
import { addInputFieldSuccess, cloneRepositoryFailed, cloneRepositoryRequest, cloneRepositorySuccess, createWorkspaceError, createWorkspaceRequest, createWorkspaceSuccess, displayNotification, displayPopUp, fetchWorkspaceDirectoryError, fetchWorkspaceDirectoryRequest, fetchWorkspaceDirectorySuccess, hideNotification, setCurrentWorkspace, setCurrentWorkspaceBranches, setCurrentWorkspaceCurrentBranch, setDeleteWorkspace, setMode, setReadOnlyMode, setRenameWorkspace, setCurrentWorkspaceIsGitRepo, setGitConfig } from './payload' import { addInputFieldSuccess, cloneRepositoryFailed, cloneRepositoryRequest, cloneRepositorySuccess, createWorkspaceError, createWorkspaceRequest, createWorkspaceSuccess, displayNotification, displayPopUp, fetchWorkspaceDirectoryError, fetchWorkspaceDirectoryRequest, fetchWorkspaceDirectorySuccess, hideNotification, setCurrentWorkspace, setCurrentWorkspaceBranches, setCurrentWorkspaceCurrentBranch, setDeleteWorkspace, setMode, setReadOnlyMode, setRenameWorkspace, setCurrentWorkspaceIsGitRepo, setGitConfig } from './payload'
import { addSlash, checkSlash, checkSpecialChars } from '@remix-ui/helper' 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 { QueryParams } from '@remix-project/remix-lib'
import * as templateWithContent from '@remix-project/remix-ws-templates' import * as templateWithContent from '@remix-project/remix-ws-templates'
import { ROOT_PATH, slitherYml, solTestYml, tsSolTestYml } from '../utils/constants' import { ROOT_PATH, slitherYml, solTestYml, tsSolTestYml } from '../utils/constants'
@ -58,8 +58,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) => { 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 provider = plugin.fileManager.currentFileProvider()
const promise = new Promise((resolve, reject) => { const promise: Promise<FileTree> = new Promise((resolve, reject) => {
provider.resolveDirectory(path, (error, fileTree) => { provider.resolveDirectory(path, (error, fileTree: FileTree) => {
if (error) { if (error) {
cb && cb(error) cb && cb(error)
return reject(error) return reject(error)
@ -85,7 +85,7 @@ const removeSlash = (s: string) => {
export const createWorkspace = async (workspaceName: string, workspaceTemplateName: WorkspaceTemplate, opts = null, isEmpty = false, cb?: (err: Error, result?: string | number | boolean | Record<string, any>) => void, isGitRepo: boolean = false, createCommit: boolean = true) => { export const createWorkspace = async (workspaceName: string, workspaceTemplateName: WorkspaceTemplate, opts = null, isEmpty = false, cb?: (err: Error, result?: string | number | boolean | Record<string, any>) => void, isGitRepo: boolean = false, createCommit: boolean = true) => {
await plugin.fileManager.closeAllFiles() await plugin.fileManager.closeAllFiles()
const promise = createWorkspaceTemplate(workspaceName, workspaceTemplateName) const promise = createWorkspaceTemplate(workspaceName, workspaceTemplateName)
dispatch(createWorkspaceRequest(promise)) dispatch(createWorkspaceRequest())
promise.then(async () => { promise.then(async () => {
dispatch(createWorkspaceSuccess({ name: workspaceName, isGitRepo })) dispatch(createWorkspaceSuccess({ name: workspaceName, isGitRepo }))
await plugin.setWorkspace({ name: workspaceName, isLocalhost: false }) await plugin.setWorkspace({ name: workspaceName, isLocalhost: false })
@ -136,10 +136,15 @@ export const createWorkspace = async (workspaceName: string, workspaceTemplateNa
const isActive = await plugin.call('manager', 'isActive', 'dgit') const isActive = await plugin.call('manager', 'isActive', 'dgit')
if (!isActive) await plugin.call('manager', 'activatePlugin', 'dgit') if (!isActive) await plugin.call('manager', 'activatePlugin', 'dgit')
} }
if (workspaceTemplateName === 'semaphore') {
const isCircomActive = await plugin.call('manager', 'isActive', 'circuit-compiler')
if (!isCircomActive) await plugin.call('manager', 'activatePlugin', 'circuit-compiler')
}
// this call needs to be here after the callback because it calls dGitProvider which also calls this function and that would cause an infinite loop // this call needs to be here after the callback because it calls dGitProvider which also calls this function and that would cause an infinite loop
await plugin.setWorkspaces(await getWorkspaces()) await plugin.setWorkspaces(await getWorkspaces())
}).catch((error) => { }).catch((error) => {
dispatch(createWorkspaceError({ error })) dispatch(createWorkspaceError(error.message))
cb && cb(error) cb && cb(error)
}) })
return promise return promise
@ -269,19 +274,19 @@ export const workspaceExists = async (name: string) => {
export const fetchWorkspaceDirectory = async (path: string) => { export const fetchWorkspaceDirectory = async (path: string) => {
if (!path) return if (!path) return
const provider = plugin.fileManager.currentFileProvider() const provider = plugin.fileManager.currentFileProvider()
const promise = new Promise((resolve) => { const promise: Promise<FileTree> = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree) => { provider.resolveDirectory(path, (error, fileTree: FileTree) => {
if (error) console.error(error) if (error) console.error(error)
resolve(fileTree) resolve(fileTree)
}) })
}) })
dispatch(fetchWorkspaceDirectoryRequest(promise)) dispatch(fetchWorkspaceDirectoryRequest())
promise.then((fileTree) => { promise.then((fileTree) => {
dispatch(fetchWorkspaceDirectorySuccess(path, fileTree)) dispatch(fetchWorkspaceDirectorySuccess(path, fileTree))
}).catch((error) => { }).catch((error) => {
dispatch(fetchWorkspaceDirectoryError({ error })) dispatch(fetchWorkspaceDirectoryError(error.message))
}) })
return promise return promise
} }

@ -3,7 +3,7 @@ import {useIntl} from 'react-intl'
import {TreeView} from '@remix-ui/tree-view' // eslint-disable-line import {TreeView} from '@remix-ui/tree-view' // eslint-disable-line
import {FileExplorerMenu} from './file-explorer-menu' // eslint-disable-line import {FileExplorerMenu} from './file-explorer-menu' // eslint-disable-line
import {FileExplorerContextMenu} from './file-explorer-context-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 '../css/file-explorer.css'
import {checkSpecialChars, extractNameFromKey, extractParentFromKey, joinPath} from '@remix-ui/helper' 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) { if (!state.ctrlKey) {
props.dispatchHandleClickFile(path, type) props.dispatchHandleClickFile(path, type)
} else { } else {

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

@ -1,12 +1,8 @@
import {extractNameFromKey} from '@remix-ui/helper' import {extractNameFromKey} from '@remix-ui/helper'
import {action, FileType} from '../types' import {action, Actions, FileType, WorkspaceElement} from '../types'
import * as _ from 'lodash' import * as _ from 'lodash'
import {fileDecoration} from '@remix-ui/file-decorators' import {fileDecoration} from '@remix-ui/file-decorators'
import {ROOT_PATH} from '../utils/constants' import {ROOT_PATH} from '../utils/constants'
interface Action {
type: string
payload: any
}
export interface BrowserState { export interface BrowserState {
browser: { browser: {
currentWorkspace: string currentWorkspace: string
@ -63,7 +59,7 @@ export interface BrowserState {
readonly: boolean readonly: boolean
popup: string popup: string
focusEdit: string focusEdit: string
focusElement: {key: string; type: 'file' | 'folder' | 'gist'}[] focusElement: {key: string; type: WorkspaceElement}[]
initializingFS: boolean initializingFS: boolean
gitConfig: {username: string; email: string; token: string} gitConfig: {username: string; email: string; token: string}
} }
@ -121,15 +117,10 @@ export const browserInitialState: BrowserState = {
gitConfig: {username: '', email: '', token: ''} gitConfig: {username: '', email: '', token: ''}
} }
export const browserReducer = (state = browserInitialState, action: Action) => { export const browserReducer = (state = browserInitialState, action: Actions) => {
switch (action.type) { switch (action.type) {
case 'SET_CURRENT_WORKSPACE': { case 'SET_CURRENT_WORKSPACE': {
const payload = action.payload as { const payload = action.payload
name: string
isGitRepo: boolean
branches?: {remote: any; name: string}[]
currentBranch?: string
}
const workspaces = state.browser.workspaces.find( const workspaces = state.browser.workspaces.find(
({name}) => name === payload.name ({name}) => name === payload.name
) )
@ -147,12 +138,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'SET_WORKSPACES': { case 'SET_WORKSPACES': {
const payload = action.payload as { const payload = action.payload
name: string
isGitRepo: boolean
branches?: {remote: any; name: string}[]
currentBranch?: string
}[]
return { return {
...state, ...state,
@ -164,7 +150,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'SET_MODE': { case 'SET_MODE': {
const payload = action.payload as 'browser' | 'localhost' const payload = action.payload
return { return {
...state, ...state,
@ -191,7 +177,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'FETCH_DIRECTORY_SUCCESS': { case 'FETCH_DIRECTORY_SUCCESS': {
const payload = action.payload as {path: string; fileTree} const payload = action.payload
return { return {
...state, ...state,
@ -255,7 +241,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'FETCH_WORKSPACE_DIRECTORY_SUCCESS': { case 'FETCH_WORKSPACE_DIRECTORY_SUCCESS': {
const payload = action.payload as {path: string; fileTree} const payload = action.payload
return { return {
...state, ...state,
@ -302,14 +288,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'DISPLAY_NOTIFICATION': { case 'DISPLAY_NOTIFICATION': {
const payload = action.payload as { const payload = action.payload
title: string
message: string
actionOk: () => void
actionCancel: () => void
labelOk: string
labelCancel: string
}
return { return {
...state, ...state,
@ -335,7 +314,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'FILE_ADDED_SUCCESS': { case 'FILE_ADDED_SUCCESS': {
const payload = action.payload as string const payload = action.payload
return { return {
...state, ...state,
@ -365,11 +344,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'FOLDER_ADDED_SUCCESS': { case 'FOLDER_ADDED_SUCCESS': {
const payload = action.payload as { const payload = action.payload
path: string
folderPath: string
fileTree
}
return { return {
...state, ...state,
@ -404,7 +379,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'FILE_REMOVED_SUCCESS': { case 'FILE_REMOVED_SUCCESS': {
const payload = action.payload as string const payload = action.payload
return { return {
...state, ...state,
@ -446,11 +421,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'ADD_INPUT_FIELD': { case 'ADD_INPUT_FIELD': {
const payload = action.payload as { const payload = action.payload
path: string
fileTree
type: 'file' | 'folder'
}
return { return {
...state, ...state,
@ -473,7 +444,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'REMOVE_INPUT_FIELD': { case 'REMOVE_INPUT_FIELD': {
const payload = action.payload as {path: string; fileTree} const payload = action.payload
return { return {
...state, ...state,
@ -496,7 +467,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'SET_READ_ONLY_MODE': { case 'SET_READ_ONLY_MODE': {
const payload = action.payload as boolean const payload = action.payload
return { return {
...state, ...state,
@ -505,11 +476,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'FILE_RENAMED_SUCCESS': { case 'FILE_RENAMED_SUCCESS': {
const payload = action.payload as { const payload = action.payload
path: string
oldPath: string
fileTree
}
return { return {
...state, ...state,
@ -543,12 +510,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'CREATE_WORKSPACE_SUCCESS': { case 'CREATE_WORKSPACE_SUCCESS': {
const payload = action.payload as { const payload = action.payload
name: string
isGitRepo: boolean
branches?: {remote: any; name: string}[]
currentBranch?: string
}
const workspaces = state.browser.workspaces.find( const workspaces = state.browser.workspaces.find(
({name}) => name === payload.name ({name}) => name === payload.name
) )
@ -581,7 +543,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'RENAME_WORKSPACE': { case 'RENAME_WORKSPACE': {
const payload = action.payload as {oldName: string; workspaceName: string} const payload = action.payload
let renamedWorkspace let renamedWorkspace
const workspaces = state.browser.workspaces.filter( const workspaces = state.browser.workspaces.filter(
({name, isGitRepo, branches, currentBranch}) => { ({name, isGitRepo, branches, currentBranch}) => {
@ -611,7 +573,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'DELETE_WORKSPACE': { case 'DELETE_WORKSPACE': {
const payload = action.payload as string const payload = action.payload
const workspaces = state.browser.workspaces.filter( const workspaces = state.browser.workspaces.filter(
({name}) => name && name !== payload ({name}) => name && name !== payload
) )
@ -626,7 +588,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'DISPLAY_POPUP_MESSAGE': { case 'DISPLAY_POPUP_MESSAGE': {
const payload = action.payload as string const payload = action.payload
return { return {
...state, ...state,
@ -642,10 +604,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'SET_FOCUS_ELEMENT': { case 'SET_FOCUS_ELEMENT': {
const payload = action.payload as { const payload = action.payload
key: string
type: 'file' | 'folder' | 'gist'
}[]
return { return {
...state, ...state,
@ -654,7 +613,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'REMOVE_FOCUS_ELEMENT': { case 'REMOVE_FOCUS_ELEMENT': {
const payload: string = action.payload const payload = action.payload
return { return {
...state, ...state,
@ -665,7 +624,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'SET_CONTEXT_MENU_ITEM': { case 'SET_CONTEXT_MENU_ITEM': {
const payload = action.payload as action const payload = action.payload
return { return {
...state, ...state,
@ -801,7 +760,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'SET_CURRENT_WORKSPACE_BRANCHES': { case 'SET_CURRENT_WORKSPACE_BRANCHES': {
const payload: {remote: any; name: string}[] = action.payload const payload = action.payload
return { return {
...state, ...state,
@ -817,7 +776,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'SET_CURRENT_WORKSPACE_CURRENT_BRANCH': { case 'SET_CURRENT_WORKSPACE_CURRENT_BRANCH': {
const payload: string = action.payload const payload = action.payload
return { return {
...state, ...state,
@ -833,7 +792,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'SET_CURRENT_WORKSPACE_IS_GITREPO': { case 'SET_CURRENT_WORKSPACE_IS_GITREPO': {
const payload: boolean = action.payload const payload = action.payload
return { return {
...state, ...state,
@ -849,7 +808,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
case 'SET_GIT_CONFIG': { case 'SET_GIT_CONFIG': {
const payload: {username: string; token: string; email: string} = const payload =
action.payload action.payload
return { return {
...state, ...state,
@ -1138,7 +1097,7 @@ const addContextMenuItem = (
const removeContextMenuItem = ( const removeContextMenuItem = (
state: BrowserState, state: BrowserState,
plugin plugin: {name: string}
): { ): {
registeredMenuItems: action[] registeredMenuItems: action[]
removedMenuItems: 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 {FormattedMessage, useIntl} from 'react-intl'
import {Dropdown} from 'react-bootstrap' 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 {FileExplorer} from './components/file-explorer' // eslint-disable-line
import {FileSystemContext} from './contexts' import {FileSystemContext} from './contexts'
import './css/remix-ui-workspace.css' import './css/remix-ui-workspace.css'
@ -385,7 +385,6 @@ export function Workspace() {
// @ts-ignore // @ts-ignore
uupsRadioRef.current.checked = false uupsRadioRef.current.checked = false
} else displayOzCustomRef.current.style.display = 'none' } else displayOzCustomRef.current.style.display = 'none'
// @ts-ignore // @ts-ignore
let displayName = TEMPLATE_NAMES[(workspaceCreateTemplateInput.current && workspaceCreateTemplateInput.current.value) || 'remixDefault'] let displayName = TEMPLATE_NAMES[(workspaceCreateTemplateInput.current && workspaceCreateTemplateInput.current.value) || 'remixDefault']
displayName = global.plugin.getAvailableWorkspaceName(displayName) displayName = global.plugin.getAvailableWorkspaceName(displayName)
@ -729,6 +728,11 @@ export function Workspace() {
{intl.formatMessage({id: 'filePanel.multiSigWallet'})} {intl.formatMessage({id: 'filePanel.multiSigWallet'})}
</option> </option>
</optgroup> </optgroup>
<optgroup style={{fontSize: 'medium'}} label="Circom ZKP">
<option style={{fontSize: 'small'}} value="semaphore">
{intl.formatMessage({id: 'filePanel.semaphore'})}
</option>
</optgroup>
</select> </select>
<div id="ozcustomization" data-id="ozCustomization" ref={displayOzCustomRef} style={{display: 'none'}} className="mb-2"> <div id="ozcustomization" data-id="ozCustomization" ref={displayOzCustomRef} style={{display: 'none'}} className="mb-2">

@ -5,7 +5,7 @@ import { fileDecoration } from '@remix-ui/file-decorators'
import { RemixAppManager } from 'libs/remix-ui/plugin-manager/src/types' import { RemixAppManager } from 'libs/remix-ui/plugin-manager/src/types'
import { ViewPlugin } from '@remixproject/engine-web' 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 { export interface JSONStandardInput {
language: "Solidity"; language: "Solidity";
settings?: any, settings?: any,
@ -17,7 +17,7 @@ export interface JSONStandardInput {
}; };
} }
export type MenuItems = action[] export type MenuItems = action[]
export type WorkspaceTemplate = 'gist-template' | 'code-template' | 'remixDefault' | 'blank' | 'ozerc20' | 'zeroxErc20' | 'ozerc721' export type WorkspaceTemplate = 'gist-template' | 'code-template' | 'remixDefault' | 'blank' | 'ozerc20' | 'zeroxErc20' | 'ozerc721' | 'semaphore'
export interface WorkspaceProps { export interface WorkspaceProps {
plugin: FilePanelType plugin: FilePanelType
} }
@ -88,7 +88,7 @@ export interface FileExplorerProps {
focusEdit: string, focusEdit: string,
hideIconsMenu: React.Dispatch<React.SetStateAction<boolean>>, hideIconsMenu: React.Dispatch<React.SetStateAction<boolean>>,
showIconsMenu: boolean, showIconsMenu: boolean,
focusElement: { key: string, type: 'file' | 'folder' | 'gist' }[], focusElement: { key: string, type: WorkspaceElement }[],
dispatchCreateNewFile: (path: string, rootDir: string) => Promise<void>, dispatchCreateNewFile: (path: string, rootDir: string) => Promise<void>,
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
modal:(title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => void, modal:(title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => void,
@ -105,8 +105,8 @@ export interface FileExplorerProps {
dispatchRunScript: (path: string) => Promise<void>, dispatchRunScript: (path: string) => Promise<void>,
dispatchPublishToGist: (path?: string, type?: string) => Promise<void>, dispatchPublishToGist: (path?: string, type?: string) => Promise<void>,
dispatchEmitContextMenuEvent: (cmd: customAction) => Promise<void>, dispatchEmitContextMenuEvent: (cmd: customAction) => Promise<void>,
dispatchHandleClickFile: (path: string, type: 'file' | 'folder' | 'gist') => Promise<void>, dispatchHandleClickFile: (path: string, type: WorkspaceElement) => Promise<void>,
dispatchSetFocusElement: (elements: { key: string, type: 'file' | 'folder' | 'gist' }[]) => Promise<void>, dispatchSetFocusElement: (elements: { key: string, type: WorkspaceElement }[]) => Promise<void>,
dispatchFetchDirectory:(path: string) => Promise<void>, dispatchFetchDirectory:(path: string) => Promise<void>,
dispatchRemoveInputField:(path: string) => Promise<void>, dispatchRemoveInputField:(path: string) => Promise<void>,
dispatchAddInputField:(path: string, type: 'file' | 'folder') => Promise<void>, dispatchAddInputField:(path: string, type: 'file' | 'folder') => Promise<void>,
@ -114,7 +114,7 @@ export interface FileExplorerProps {
dispatchMoveFile: (src: string, dest: string) => Promise<void>, dispatchMoveFile: (src: string, dest: string) => Promise<void>,
dispatchMoveFolder: (src: string, dest: string) => Promise<void>, dispatchMoveFolder: (src: string, dest: string) => Promise<void>,
handlePasteClick: (dest: string, destType: string) => void handlePasteClick: (dest: string, destType: string) => void
handleCopyClick: (path: string, type: 'folder' | 'gist' | 'file' | 'workspace') => void handleCopyClick: (path: string, type: WorkspaceElement) => void
addMenuItems: (items: MenuItems) => void addMenuItems: (items: MenuItems) => void
removeMenuItems: (items: MenuItems) => void removeMenuItems: (items: MenuItems) => void
handleContextMenu: (pageX: number, pageY: number, path: string, content: string, type: string) => void handleContextMenu: (pageX: number, pageY: number, path: string, content: string, type: string) => void
@ -171,7 +171,7 @@ export interface WorkSpaceState {
actions: { actions: {
id: string id: string
name: string name: string
type?: Array<'folder' | 'gist' | 'file' | 'workspace'> type?: Array<WorkspaceElement>
path?: string[] path?: string[]
extension?: string[] extension?: string[]
pattern?: string[] pattern?: string[]
@ -201,5 +201,107 @@ export type FileFocusContextType = {
export type CopyElementType = { export type CopyElementType = {
key: string 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'

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

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

@ -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)
}
}
}
Loading…
Cancel
Save