├── .eslintignore ├── .eslintrc ├── .github └── workflows │ └── release.yml ├── .gitignore ├── .npmrc ├── README.md ├── bin └── cle.js ├── build.config.ts ├── package.json ├── pnpm-lock.yaml ├── src ├── cli.ts ├── commands │ ├── compile.ts │ ├── create.ts │ ├── deposit.ts │ ├── exec.ts │ ├── prove.ts │ ├── publish.ts │ ├── setup.ts │ ├── upload.ts │ └── verify.ts ├── config.ts ├── constants.ts ├── index.ts ├── logger.ts ├── tag.ts └── utils │ ├── cli.ts │ ├── dsp.ts │ ├── file.ts │ ├── index.ts │ ├── load.ts │ ├── log.ts │ ├── network.ts │ ├── path.ts │ ├── pinata.ts │ ├── td.ts │ └── utils.ts ├── test ├── __snapshots__ │ └── config.test.ts.snap ├── cli.test.ts ├── compile.test.ts ├── config.test.ts ├── dsp.test.ts ├── exec.test.ts ├── file.test.ts ├── fixtures │ ├── commands │ │ ├── cle.yaml │ │ └── mapping.ts │ ├── config │ │ ├── cle.config.ts │ │ ├── cle.func.config.ts │ │ ├── cle.merge.config.ts │ │ └── cle.object.config.ts │ └── utils │ │ ├── proof_0000.txt │ │ ├── proof_1111.txt │ │ ├── proof_65d9c90f429af08ed921eb29.txt │ │ ├── test-yaml-check.yaml │ │ ├── test.yaml │ │ └── ts_files │ │ ├── 3 │ │ ├── 4 │ │ │ └── 4.ts │ │ └── 3.ts │ │ ├── 1.ts │ │ └── 2.ts ├── mock │ └── dsp.ts ├── parse-tag.test.ts ├── prove.test.ts ├── setup.test.ts ├── utils.test.ts └── utils │ ├── error.ts │ ├── node.ts │ └── utils.ts └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | packages/create-cle/template-*/**/* 2 | test/fixtures/**/* 3 | packages/create-cle/templates/**/**/* 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@murongg" 3 | } 4 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | push: 8 | tags: 9 | - 'v*' 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 18 | 19 | - name: Install pnpm 20 | uses: pnpm/action-setup@v2 21 | 22 | - name: Set node 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: 18.x 26 | 27 | - run: npx changelogithub 28 | env: 29 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .DS_Store 3 | .idea 4 | *.log 5 | *.tgz 6 | coverage 7 | dist 8 | lib-cov 9 | logs 10 | node_modules 11 | temp 12 | 13 | test/fixtures/**/entry_*.ts 14 | test/fixtures/**/proof.txt 15 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | ignore-workspace-root-check=true 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CLE CLI 2 | 3 | ## Getting Started 4 | 5 | ### Creating Your First CLE Project 6 | 7 | With NPM: 8 | ```bash 9 | npm create cle@latest 10 | ``` 11 | 12 | With Yarn: 13 | 14 | ```bash 15 | yarn create cle@latest 16 | ``` 17 | 18 | With PNPM: 19 | 20 | ```bash 21 | pnpm create cle@latest 22 | ``` 23 | 24 | Then follow the prompts! 25 | 26 | To create a **uniswapprice** template, you can directly specify the project name and the desired template using additional command line options. For instance, you can run the following command: 27 | 28 | ```sh 29 | # npm 6.x 30 | npm create cle@latest my-cle-uniswapprice --template uniswapprice 31 | 32 | # npm 7+, extra double-dash is needed: 33 | npm create cle@latest my-cle-uniswapprice -- --template uniswapprice 34 | 35 | # yarn 36 | yarn create cle@latest my-cle-uniswapprice --template uniswapprice 37 | 38 | # pnpm 39 | pnpm create cle@latest my-cle-uniswapprice --template uniswapprice 40 | ``` 41 | 42 | ## CLI 43 | 44 | > Note: `unsafe` (define `unsafe: true` in the `cle.yaml`) means the CLE is compiled locally and only contains partial computation (so that proving and executing will be faster). 45 | 46 | The workflow of local CLE development must follow: `Develop` (code in /src) -> `Compile` (get compiled wasm image) -> `Execute` (get expected output) -> `Prove` (generate input and pre-test for actual proving in zkOracle) -> `Verify` (verify proof on-chain). 47 | 48 | To upload and publish your CLE, you should `Upload` (upload code to IPFS), and then `Publish` (register CLE on onchain CLE Registry). 49 | 50 | ### Compile 51 | 52 | Compile for Full Image (Link Compiled with Compiler Server). 53 | 54 | #### Usage 55 | 56 | ```bash 57 | cle compile [root] 58 | ``` 59 | 60 | #### Options 61 | 62 | | Options | Description | 63 | | -------------------- | ------------------------------------- | 64 | | `--yaml-path ` | Path to yaml file | 65 | | `--dir ` | Path to directory containing cle.yaml | 66 | 67 | ### Execute 68 | 69 | Execute Full Image. 70 | 71 | Please save the `CLE_STATE_OUTPUT` string for following prove steps. 72 | 73 | #### Usage 74 | ```bash 75 | cle exec [...params] [root] 76 | ``` 77 | 78 | #### Usage cases 79 | ```bash 80 | cle exec [root] 81 | cle exec [root] 82 | ``` 83 | 84 | 85 | #### Arguments 86 | 87 | | Arguments | Description | 88 | | ---------------- | ----------------------------------------------- | 89 | | `` | Block number (or block hash) as runtime context | 90 | | `` | offchain data | 91 | 92 | 93 | ### Set Up 94 | 95 | Set Up Full Image 96 | 97 | - `circuit-size`: Specify the circuit size of image instead of the default recommended. eg. `cle setup -- --circuit-size (eg. 22)`. 98 | 99 | #### Usage 100 | ```bash 101 | cle setup [root] 102 | ``` 103 | 104 | #### Options 105 | 106 | | Options | Description | 107 | | --------------------------- | -------------------------------- | 108 | | `-k, --circuit-size ` | Circuit size (k in 2^k) of image | 109 | 110 | ### Prove 111 | 112 | Prove Full Image 113 | 114 | #### Usage 115 | ```bash 116 | cle prove [...params] [root] 117 | ``` 118 | 119 | #### Usage cases 120 | ```bash 121 | cle prove [root] 122 | cle prove [root] 123 | ``` 124 | 125 | #### Arguments 126 | 127 | | Arguments | Description | 128 | | ------------------ | ----------------------------------------------- | 129 | | `` | Block number (or block hash) as runtime context | 130 | | `` | State output of the CLE execution | 131 | | `` | offchain data | 132 | 133 | 134 | #### Options 135 | 136 | | Options | Description | 137 | | ---------------- | ---------------------------- | 138 | | `-i, --inputgen` | Run in input generation Mode | 139 | | `-t, --test` | Run in test Mode | 140 | | `-p, --prove` | Run in prove Mode | 141 | 142 | ### Upload 143 | 144 | Upload CLE (Code and Full Image). 145 | 146 | Please save the `ipfs_hash` from the output dialog for following publish steps. 147 | 148 | #### Usage 149 | ```bash 150 | cle upload [root] 151 | ``` 152 | 153 | 154 | ### Verify 155 | 156 | Verify Proof Onchain. 157 | 158 | #### Usage 159 | ```bash 160 | cle verify 161 | ``` 162 | 163 | #### Arguments 164 | 165 | | Arguments | Description | 166 | | ----------------- | --------------------- | 167 | | `` | Task id of prove task | 168 | 169 | 170 | ### Publish 171 | 172 | Publish and Register CLE Onchain. 173 | 174 | See also: [Verifier Contract Interface](https://github.com/DelphinusLab/halo2aggregator-s/blob/main/sol/contracts/AggregatorVerifier.sol#L40). 175 | 176 | #### Usage 177 | ```bash 178 | cle publish [bounty_reward_per_trigger] 179 | ``` 180 | 181 | #### Arguments 182 | 183 | | Arguments | Description | 184 | | ----------------------------- | -------------------------------- | 185 | | `` | IPFS hash of uploaded CLE | 186 | | `[bounty reward per trigger]` | Bounty reward per trigger in ETH | 187 | 188 | ### Deposit 189 | 190 | Publish and register CLE Onchain. 191 | 192 | #### Usage 193 | ```bash 194 | cle deposit 195 | ``` 196 | 197 | #### Arguments 198 | 199 | | Arguments | Description | 200 | | ----------------------------- | ---------------------------------------------------------- | 201 | | `` | Contract address of deployed verification contract address | 202 | | `` | Deposit amount in ETH | 203 | 204 | ## Config 205 | 206 | ### Configuring CLE 207 | 208 | When running CLE from the command line, the tool will automatically attempt to locate a configuration file named cle.config.js in the project’s root directory. It also supports other file extensions such as JS and TS. 209 | 210 | The most basic config file looks like this: 211 | 212 | ```js 213 | // cle.config.js 214 | export default { 215 | // config options 216 | } 217 | ``` 218 | 219 | You can also explicitly specify a config file to use with the --config CLI option (resolved relative to cwd): 220 | 221 | ```bash 222 | cle --config my-config.js 223 | ``` 224 | 225 | ### Config Intellisense 226 | 227 | Since CLE ships with TypeScript typings, you can leverage your IDE's intellisense with jsdoc type hints: 228 | 229 | ```js 230 | /** @type {import('@ora-io/cle-cli').UserConfig} */ 231 | export default { 232 | // ... 233 | } 234 | ``` 235 | Alternatively, you can use the defineConfig helper which should provide intellisense without the need for jsdoc annotations: 236 | 237 | ```js 238 | import { defineConfig } from '@ora-io/cle-cli' 239 | 240 | export default defineConfig({ 241 | // ... 242 | }) 243 | ``` 244 | 245 | CLE also directly supports TS config files. You can use cle.config.ts with the defineConfig helper as well. 246 | 247 | ### Config Options 248 | 249 | #### JsonRpcProviderUrl 250 | 251 | - **Type:** `object` 252 | - **Default**: `{ mainet: "", sepolia: "", goerli: ""}` 253 | 254 | Update your Etherum JSON RPC provider URL here. 255 | It is recommended to use providers that support debug_getRawReceipts RPC method. 256 | 257 | #### UserPrivateKey 258 | 259 | - **Type:** `string` 260 | 261 | Update your private key here to sign messages & send txs. 262 | The CLI will inform you before sending out any tx. 263 | The `cle.config.ts` is in `.gitignore` by default. CLI will never upload / disclose your private key by default. 264 | 265 | #### ProverProviderUrl 266 | 267 | - **Type:** `string` 268 | - **Default**: `https://rpc.zkwasmhub.com:8090` 269 | 270 | #### CompilerServerEndpoint 271 | 272 | - **Type:** `string` 273 | - **Default**: `https://compiler.ora.io/compile/` 274 | 275 | #### PinataEndpoint 276 | 277 | - **Type:** `string` 278 | - **Default**: `https://api.pinata.cloud/pinning/pinFileToIPFS` 279 | 280 | #### PinataJWT 281 | 282 | - **Type:** `string` 283 | 284 | #### WasmBinPath 285 | 286 | - **Type:** `string` 287 | - **Default**: `[root]/build/cle.wasm` 288 | 289 | CLE CLI Build-In a tag name is `root`. 290 | The `root` is user project root path. 291 | Of course, you can also place this tag at any position within the string. 292 | -------------------------------------------------------------------------------- /bin/cle.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict' 3 | const { run } = require('../dist/index.cjs') 4 | 5 | run() 6 | -------------------------------------------------------------------------------- /build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild' 2 | 3 | export default defineBuildConfig({ 4 | entries: [ 5 | 'src/index', 6 | ], 7 | declaration: true, 8 | clean: true, 9 | rollup: { 10 | emitCJS: true, 11 | }, 12 | }) 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ora-io/cle-cli", 3 | "version": "0.1.6", 4 | "packageManager": "pnpm@8.6.0", 5 | "description": "", 6 | "homepage": "https://github.com/ora-io/cle-cli#readme", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/ora-io/cle-cli.git", 10 | "directory": "packages/cle-cli" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/ora-io/cle-cli/issues" 14 | }, 15 | "keywords": [], 16 | "sideEffects": false, 17 | "exports": { 18 | ".": { 19 | "types": "./dist/index.d.ts", 20 | "require": "./dist/index.cjs", 21 | "import": "./dist/index.mjs" 22 | } 23 | }, 24 | "main": "./dist/index.mjs", 25 | "module": "./dist/index.mjs", 26 | "types": "./dist/index.d.ts", 27 | "typesVersions": { 28 | "*": { 29 | "*": [ 30 | "./dist/*", 31 | "./dist/index.d.ts" 32 | ] 33 | } 34 | }, 35 | "bin": { 36 | "cle": "bin/cle.js" 37 | }, 38 | "files": [ 39 | "dist", 40 | "bin" 41 | ], 42 | "scripts": { 43 | "clean": "rimraf dist", 44 | "build": "unbuild", 45 | "lint": "eslint .", 46 | "lint:fix": "eslint . --fix", 47 | "prepublishOnly": "nr build", 48 | "release": "cle-scripts release && cle-scripts publish", 49 | "test": "vitest", 50 | "typecheck": "tsc --noEmit" 51 | }, 52 | "peerDependencies": { 53 | "@ora-io/cle-lib": "^0.1.3" 54 | }, 55 | "dependencies": { 56 | "@ora-io/cle-api": "^0.1.5", 57 | "@ora-io/zkwasm-service-helper": "^1.0.3", 58 | "api": "^6.1.1", 59 | "await-to-js": "^3.0.0", 60 | "axios": "^1.5.1", 61 | "axios-retry": "^3.8.0", 62 | "cac": "^6.7.14", 63 | "create-cle": "^0.1.1", 64 | "ethers": "^5.7.2", 65 | "form-data": "^4.0.0", 66 | "nanoid": "^5.0.1", 67 | "picocolors": "^1.0.0", 68 | "prompts": "^2.4.2", 69 | "semver": "^7.5.4", 70 | "ts-md5": "^1.3.1", 71 | "unconfig": "^0.3.11" 72 | }, 73 | "devDependencies": { 74 | "@murongg/eslint-config": "^0.2.1", 75 | "@ora-io/cle-lib": "^0.1.3", 76 | "@ora-io/release-scripts": "^0.0.1", 77 | "@types/fs-extra": "^11.0.4", 78 | "@types/js-yaml": "^4.0.6", 79 | "@types/prompts": "^2.4.6", 80 | "@types/semver": "^7.5.3", 81 | "assemblyscript": "^0.27.24", 82 | "consola": "^3.2.3", 83 | "eslint": "^8.57.0", 84 | "fast-glob": "^3.3.2", 85 | "fs-extra": "^11.2.0", 86 | "lint-staged": "^15.2.2", 87 | "rimraf": "^5.0.5", 88 | "simple-git-hooks": "^2.9.0", 89 | "typescript": "^5.3.3", 90 | "unbuild": "^2.0.0", 91 | "vitest": "^1.3.1", 92 | "zkwasm-toolchain": "^0.0.4" 93 | }, 94 | "simple-git-hooks": { 95 | "pre-commit": "pnpm lint-staged" 96 | }, 97 | "lint-staged": { 98 | "*": "eslint --fix" 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/cli.ts: -------------------------------------------------------------------------------- 1 | import cac from 'cac' 2 | import { version } from '../package.json' 3 | import { compile } from './commands/compile' 4 | import { exec } from './commands/exec' 5 | import { setup } from './commands/setup' 6 | import { prove as proveHandler } from './commands/prove' 7 | import { upload } from './commands/upload' 8 | import { verify } from './commands/verify' 9 | import { publish } from './commands/publish' 10 | import { getConfig } from './config' 11 | import { createLogger, logger, setLogger } from './logger' 12 | import { create } from './commands/create' 13 | import { generateCommandUsage, proveCLIHasModeOption } from './utils' 14 | import { deposit } from './commands/deposit' 15 | 16 | export async function run() { 17 | try { 18 | const cli = cac('cle') 19 | 20 | const config = await getConfig() 21 | setLogger(createLogger(config.logger?.level || 'info')) 22 | 23 | const { proveUsage, execUsage } = generateCommandUsage() 24 | cli 25 | .command('compile', 'Compile for Full Image (Link Compiled with Compiler Server)') 26 | // .option('--local', 'Compile for Local Image') 27 | .option('--yaml-path ', 'Path to yaml file') 28 | .option('--dir ', 'Path to directory containing cle.yaml') 29 | .example('cle compile') 30 | .action((options) => { 31 | const { yamlPath = '', dir } = options 32 | const wasmPath = config.WasmBinPath 33 | 34 | compile({ 35 | // local, 36 | yamlPath: yamlPath || config.YamlPath, 37 | compilerServerEndpoint: config.CompilerServerEndpoint, 38 | wasmPath, 39 | watPath: wasmPath.replace(/\.wasm/, '.wat'), 40 | dirPath: dir, 41 | }) 42 | }) 43 | 44 | cli 45 | .command('exec [...params]', 'Execute Full Image') 46 | // .option('--local', 'Execute Local Image') 47 | .example('cle exec 0000000') 48 | .action((params, _options) => { 49 | // const { local = false } = options 50 | const wasmPath = config.WasmBinPath 51 | 52 | exec({ 53 | // local, 54 | wasmPath, 55 | yamlPath: config.YamlPath, 56 | jsonRpcProviderUrl: config.JsonRpcProviderUrl, 57 | params, 58 | }) 59 | }) 60 | .usage(`[...params] 61 | 62 | Usage cases: 63 | ${execUsage}`) 64 | 65 | cli 66 | .command('setup', 'Set Up Full Image') 67 | // .option('--local', 'Set Up Local Image') 68 | .option('-k, --circuit-size ', 'Circuit size (k in 2^k) of image') 69 | .example('cle setup -k 20') 70 | .action((options) => { 71 | // const { circuitSize = '', local = false } = options 72 | const { circuitSize = '' } = options 73 | const wasmPath = config.WasmBinPath 74 | const size = !circuitSize || circuitSize === 0 ? 22 : Number(circuitSize) 75 | setup({ 76 | circuitSize: size, 77 | wasmPath, 78 | userPrivateKey: config.UserPrivateKey, 79 | ProverProviderUrl: config.ProverProviderUrl, 80 | }) 81 | }) 82 | 83 | const proveCLI = cli 84 | .command('prove [...params]', 'Prove Full Image') 85 | // .option('--local', 'Prove Local Image') 86 | .option('-i, --inputgen', 'Run in input generation Mode') 87 | .option('-t, --test', 'Run in test Mode') 88 | .option('-p, --prove', 'Run in prove Mode') 89 | .example('cle prove 2279547 a60ecf32309539dd84f27a9563754dca818b815e -t') 90 | .example('cle prove 2279547 a60ecf32309539dd84f27a9563754dca818b815e -i') 91 | .example('cle prove 2279547 a60ecf32309539dd84f27a9563754dca818b815e -p') 92 | .action((params, options) => { 93 | // eslint-disable-next-line prefer-const 94 | let { inputgen = false, test = false, prove = false } = options 95 | const hasMode = proveCLIHasModeOption() 96 | if (!hasMode) 97 | test = true 98 | 99 | if (!(inputgen || test || prove)) { 100 | logger.error('error: missing running mode (-i / -t / -p)\n') 101 | proveCLI.outputHelp() 102 | return 103 | } 104 | const wasmPath = config.WasmBinPath 105 | 106 | proveHandler({ 107 | params, 108 | inputgen, 109 | test, 110 | prove, 111 | // local, 112 | wasmPath, 113 | yamlPath: config.YamlPath, 114 | jsonRpcProviderUrl: config.JsonRpcProviderUrl, 115 | ProverProviderUrl: config.ProverProviderUrl, 116 | userPrivateKey: config.UserPrivateKey, 117 | outputProofFilePath: config.OutputProofFilePath, 118 | }) 119 | }) 120 | .usage(`[...params] 121 | 122 | Usage cases: 123 | ${proveUsage}`) 124 | 125 | cli 126 | .command('upload', 'Upload CLE (Code and Full Image)') 127 | // .option('--local', 'Upload Local CLE (Code and Local Image)') 128 | .example('cle upload') 129 | .action((_options) => { 130 | // const { local = false } = options 131 | upload({ 132 | // local, 133 | wasmPath: config.WasmBinPath, 134 | yamlPath: config.YamlPath, 135 | pinataEndpoint: config.PinataEndpoint, 136 | pinataJWT: config.PinataJWT, 137 | userPrivateKey: config.UserPrivateKey, 138 | }) 139 | }) 140 | 141 | cli 142 | .command('verify ', 'Verify Proof Onchain') 143 | .example('cle verify 000000') 144 | .action((taskId) => { 145 | verify({ 146 | taskId, 147 | yamlPath: config.YamlPath, 148 | ProverProviderUrl: config.ProverProviderUrl, 149 | jsonRpcProviderUrl: config.JsonRpcProviderUrl, 150 | outputProofFilePath: config.OutputProofFilePath, 151 | }) 152 | }) 153 | 154 | cli 155 | .command('publish [bounty_reward_per_trigger]', 'Publish and Register CLE Onchain') 156 | .example('cle publish 0x00000000000000000000000000000000 0') 157 | .usage(`publish [bounty_reward_per_trigger] 158 | 159 | ipfs_hash: by finishing upload get it 160 | `) 161 | .action((ipfsHash, bountyRewardPerTrigger) => { 162 | publish({ 163 | ipfsHash, 164 | bountyRewardPerTrigger: bountyRewardPerTrigger || 0, 165 | yamlPath: config.YamlPath, 166 | wasmPath: config.WasmBinPath, 167 | jsonRpcProviderUrl: config.JsonRpcProviderUrl, 168 | userPrivateKey: config.UserPrivateKey, 169 | ProverProviderUrl: config.ProverProviderUrl, 170 | }) 171 | }) 172 | 173 | cli 174 | .command('init ', 'Init CLE template') 175 | .alias('create') 176 | .option('-t, --template