diff --git a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json index 05fef4beab..57b7951f64 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json +++ b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json @@ -34,6 +34,8 @@ "filePanel.tssoltestghaction": "Mocha Chai Test Workflow", "filePanel.workspace.addscriptetherscan": "Adds scripts which can be used to interact with the Etherscan API", "filePanel.addscriptetherscan": "Add Etherscan scripts", + "filePanel.workspace.addscriptsindri": "Adds scripts for interacting with Sindri, a zk proof generation remote service", + "filePanel.addscriptsindri": "Add Sindri ZK scripts", "filePanel.workspace.addscriptdeployer": "Adds scripts which can be used to deploy contracts", "filePanel.addscriptdeployer": "Add contract deployer scripts", "filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI", diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index 98c3ef5919..fd5b09e9b0 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -42,7 +42,7 @@ import { ROOT_PATH, slitherYml, solTestYml, tsSolTestYml } from '../utils/consta import { IndexedDBStorage } from '../../../../../../apps/remix-ide/src/app/files/filesystems/indexedDB' import { getUncommittedFiles } from '../utils/gitStatusFilter' import { AppModal, ModalTypes } from '@remix-ui/app' -import { contractDeployerScripts, etherscanScripts } from '@remix-project/remix-ws-templates' +import * as templates from '@remix-project/remix-ws-templates' declare global { interface Window { @@ -869,13 +869,9 @@ export const createSlitherGithubAction = async () => { plugin.call('fileManager', 'open', path) } -const scriptsRef = { - deployer: contractDeployerScripts, - etherscan: etherscanScripts, -} export const createHelperScripts = async (script: string) => { - if (!scriptsRef[script]) return - await scriptsRef[script](plugin) + if (!templates[script]) return + await templates[script](plugin) plugin.call('notification', 'toast', 'scripts added in the "scripts" folder') } diff --git a/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx b/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx index 8960ad22c6..822490a06d 100644 --- a/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx +++ b/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx @@ -169,7 +169,7 @@ export function HamburgerMenu(props: HamburgerMenuProps) { fa="fa-kit fa-ts-logo" hideOption={hideWorkspaceOptions || hideFileOperations} actionOnClick={() => { - props.addHelperScripts('etherscan') + props.addHelperScripts('etherscanScripts') props.hideIconsMenu(!showIconsMenu) }} platforms={[appPlatformTypes.web, appPlatformTypes.desktop]} @@ -179,7 +179,17 @@ export function HamburgerMenu(props: HamburgerMenuProps) { fa="fa-kit fa-ts-logo" hideOption={hideWorkspaceOptions || hideFileOperations} actionOnClick={() => { - props.addHelperScripts('deployer') + props.addHelperScripts('contractDeployerScripts') + props.hideIconsMenu(!showIconsMenu) + }} + platforms={[appPlatformTypes.web, appPlatformTypes.desktop]} + > + { + props.addHelperScripts('sindriScripts') props.hideIconsMenu(!showIconsMenu) }} platforms={[appPlatformTypes.web, appPlatformTypes.desktop]} diff --git a/libs/remix-ws-templates/src/index.ts b/libs/remix-ws-templates/src/index.ts index 2955f961db..e0e1a4edef 100644 --- a/libs/remix-ws-templates/src/index.ts +++ b/libs/remix-ws-templates/src/index.ts @@ -12,4 +12,5 @@ export { default as rln } from './templates/rln' export { contractDeployerScripts } from './script-templates/contract-deployer' export { etherscanScripts } from './script-templates/etherscan' +export { sindriScripts } from './script-templates/sindri' diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts new file mode 100644 index 0000000000..bcf90ca0a0 --- /dev/null +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -0,0 +1,15 @@ +export const sindriScripts = async (plugin) => { + await plugin.call('fileManager', 'writeFile', + 'scripts/sindri/sindri.ts' , + // @ts-ignore + (await import('!!raw-loader!./sindri.ts')).default) + + + await plugin.call('fileManager', 'writeFile', + 'sindri.json' , + // @ts-ignore + (await import('raw-loader!./sindri.conf')).default) + + + await plugin.call('fileManager', 'open', 'scripts/sindri/sindri.ts') + } \ No newline at end of file diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf b/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf new file mode 100644 index 0000000000..204f4e7665 --- /dev/null +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf @@ -0,0 +1,8 @@ +{ + "$schema": "https://forge.sindri.app/api/v1/sindri-manifest-schema.json", + "name": "circuit name", + "circuitType": "circom", + "curve": "bn254", + "provingScheme": "groth16", + "witnessCompiler": "c++" +} \ No newline at end of file diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts new file mode 100644 index 0000000000..a7dffed601 --- /dev/null +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts @@ -0,0 +1,58 @@ +import client from 'sindri' + +/** + * Compile the given circuit + * @param {string} entryPoint - path to the circuit to compile + * @param {string} apiKey - sindri API key + * @returns {Circuit} compiled circuit + */ +export const createCircuit = async (entryPoint: string, apiKey: string) => { + client.authorize({ apiKey }) + + const sindriConf = await remix.call('fileManager', 'readFile', `sindri.json`) + const circuit = await remix.call('fileManager', 'readFile', entryPoint) + const deps = await remix.call('circuit-compiler' as any, 'resolveDependencies', entryPoint, circuit) + + const files = [] + files.push(new File([circuit], 'circuit.circom')) + files.push(new File([sindriConf], 'sindri.json')) + + for (const file in deps) { + if (file === entryPoint) continue + files.push(new File([deps[file]], file)) + } + + const circuitProject = await client.createCircuit(files) + return circuitProject +} + +/** + * Generate a proof against the given circuit + * @param {string} circuitId - id of the circuit + * @param {Object} signals - input signals + * @returns {Proof} generated proof + */ +export const proveCircuit = async (circuitId: string, signals: { [id: string]: string }, apiKey: string) => { + client.authorize({ apiKey }) + const proof = await client.proveCircuit(circuitId, JSON.stringify(signals)) + return proof +} + + +/** + * Save the circuit + * @param {Circuit} circuitProject - compiled circuit + */ +export const saveCircuit = async (circuitProject) => { + await remix.call('fileManager', 'writeFile', `.sindri/${circuitProject.circuit_id}.json`, JSON.stringify(circuitProject, null, '\t')) +} + +/** + * Load the circuit + * @param {string} circuitId - id of the circuit + * @param {Object} signals - input signals + * @returns {Proof} generated proof + */ +export const loadCircuit = async (circuitId: string) => { + return JSON.parse(await remix.call('fileManager', 'readFile', `.sindri/${circuitId}.json`)) +} \ No newline at end of file