From 1fcb964265907b07a20691c23ba26b0c2b127c97 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Fri, 5 Jan 2024 22:40:13 +0000 Subject: [PATCH] chore: Rename generate-ts/nr commands to codegen. (#3843) * Get rid of generate-* commands on cli, in favour of `codegen` command with optional `--ts` or `--nr` flags. * Update docs to explain how to do a contract compilation now. --- aztec-up/bin/aztec-sandbox | 2 +- boxes/blank-react/package.json | 2 +- boxes/blank/package.json | 2 +- boxes/token/package.json | 2 +- docs/docs/dev_docs/contracts/compiling.md | 48 ++++++++----------- yarn-project/cli/src/index.ts | 8 +--- .../add_noir_compiler_commander_actions.ts | 38 +++++---------- ...ate_typescript_interface.ts => codegen.ts} | 24 +++++++--- .../src/cli/generate_noir_interface.ts | 33 ------------- .../noir-contracts/scripts/generate-types.sh | 2 +- 10 files changed, 58 insertions(+), 103 deletions(-) rename yarn-project/noir-compiler/src/cli/{generate_typescript_interface.ts => codegen.ts} (62%) delete mode 100644 yarn-project/noir-compiler/src/cli/generate_noir_interface.ts diff --git a/aztec-up/bin/aztec-sandbox b/aztec-up/bin/aztec-sandbox index 1779b7c1538..3d1f2d85953 100755 --- a/aztec-up/bin/aztec-sandbox +++ b/aztec-up/bin/aztec-sandbox @@ -5,7 +5,7 @@ set -euo pipefail CMD="docker compose" $CMD &>/dev/null || CMD="docker-compose" -ARGS="-f ~/.aztec/docker-compose.yml -p sandbox" +ARGS="-f $HOME/.aztec/docker-compose.yml -p sandbox" # Function to be executed when SIGINT is received. cleanup() { diff --git a/boxes/blank-react/package.json b/boxes/blank-react/package.json index 60691b242b6..c337fc60019 100644 --- a/boxes/blank-react/package.json +++ b/boxes/blank-react/package.json @@ -12,7 +12,7 @@ "formatting": "prettier --check ./src && eslint ./src", "formatting:fix": "prettier -w ./src", "compile": "cd src/contracts && ${AZTEC_NARGO:-aztec-nargo} compile", - "codegen": "${AZTEC_CLI:-aztec-cli} generate-typescript src/contracts/target --outdir src/artifacts", + "codegen": "${AZTEC_CLI:-aztec-cli} codegen src/contracts/target -o src/artifacts --ts", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --runInBand" }, "jest": { diff --git a/boxes/blank/package.json b/boxes/blank/package.json index 33f02d75393..eea2e510cf2 100644 --- a/boxes/blank/package.json +++ b/boxes/blank/package.json @@ -12,7 +12,7 @@ "formatting": "prettier --check ./src && eslint ./src", "formatting:fix": "prettier -w ./src", "compile": "cd src/contracts && ${AZTEC_NARGO:-aztec-nargo} compile", - "codegen": "${AZTEC_CLI:-aztec-cli} generate-typescript src/contracts/target --outdir src/artifacts", + "codegen": "${AZTEC_CLI:-aztec-cli} codegen src/contracts/target -o src/artifacts --ts", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --runInBand" }, "jest": { diff --git a/boxes/token/package.json b/boxes/token/package.json index 7d8f3e2b640..004d953c696 100644 --- a/boxes/token/package.json +++ b/boxes/token/package.json @@ -12,7 +12,7 @@ "formatting": "prettier --check ./src && eslint ./src", "formatting:fix": "prettier -w ./src", "compile": "cd src/contracts && ${AZTEC_NARGO:-aztec-nargo} compile", - "codegen": "${AZTEC_CLI:-aztec-cli} generate-typescript src/contracts/target --outdir src/artifacts", + "codegen": "${AZTEC_CLI:-aztec-cli} codegen src/contracts/target -o src/artifacts --ts", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --runInBand" }, "jest": { diff --git a/docs/docs/dev_docs/contracts/compiling.md b/docs/docs/dev_docs/contracts/compiling.md index f6bb27dc535..a44bd6e32cd 100644 --- a/docs/docs/dev_docs/contracts/compiling.md +++ b/docs/docs/dev_docs/contracts/compiling.md @@ -6,40 +6,38 @@ In this guide we will cover how to do so, both using the CLI and programmaticall We'll also cover how to generate a helper [TypeScript interface](#typescript-interfaces) and an [Aztec.nr interface](#noir-interfaces) for easily interacting with your contract from your typescript app and from other Aztec.nr contracts, respectively. -## Compile using the CLI +## Compile using aztec-nargo -To compile a contract using the Aztec CLI, first [install it](../cli/cli-commands#installation). +To compile a contract using the Aztec's build of nargo. -Then run the `compile` command with the path to your [contract project folder](./layout.md#directory-structure), which is the one that contains the `Nargo.toml` file: +Run the `aztec-nargo compile` command within your [contract project folder](./layout.md#directory-structure), which is the one that contains the `Nargo.toml` file: -``` -aztec-cli compile ./path/to/my_aztec_contract_project +```bash +aztec-nargo compile ``` -This will output a JSON [artifact](./artifacts.md) for each contract in the project to a `target` folder containing their artifact, which you can use for deploying or interacting with your contracts. +This will output a JSON [artifact](./artifacts.md) for each contract in the project to a `target` folder containing the Noir ABI artifacts. -`aztec-cli` uses `noir_wasm` by default for compiling contracts. This helps reduce the developer overhead of installation and maintaining the noir compiler, `nargo`. However, if you prefer, you can use `nargo` to compile contracts with `aztec-cli` as so: +Before you can use the ABI it currently needs to be validated as being Aztec compatible, and transformed to an Aztec compatible ABI using `aztec-cli codegen`, passing a Noir ABI file or folder, and output location, e.g: ```bash -aztec-cli compile my-contract --compiler nargo # switches compiler to nargo +aztec-cli codegen ./aztec-nargo/output/target/path -o src/artifacts ``` -When you specify `nargo` as your compiler, you need to make sure that you are using the correct version. You can find the [latest version information here](../updating.md#updating-nargo). +It can be useful to perform this compilation, validation and transformation in one go, so you may wish to chain the commands and perhaps add them to a package.json script. The below assumes your contract is in a folder called `contract` at your project root: -### Typescript Interfaces - -You can use the compiler to autogenerate type-safe typescript classes for each of your contracts. These classes define type-safe methods for deploying and interacting with your contract based on their artifact. +```bash +(cd contract && aztec-nargo compile && aztec-cli codegen target -o ../src/artifacts) +``` -To generate them, include a `--typescript` option in the compile command with a path to the target folder for the typescript files: +### Typescript Interfaces -``` -aztec-cli compile --typescript ./path/to/typescript/src ./path/to/my_aztec_contract_project -``` +You can use the codegenerator to autogenerate type-safe typescript classes for each of your contracts. These classes define type-safe methods for deploying and interacting with your contract based on their artifact. -You can also generate these interfaces from prebuilt artifacts using the `generate-typescript` command: +To generate them, include a `--ts` option in the codegen command with a path to the target folder for the typescript files: -``` -aztec-cli generate-typescript ./path/to/my_aztec_contract_project +```bash +aztec-cli codegen ./aztec-nargo/output/target/path -o src/artifacts --ts ``` Below is typescript code generated from the [Token](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/token_contract/src/main.nr) contract: @@ -133,16 +131,10 @@ An Aztec.nr contract can [call a function](./syntax/functions.md) in another con To make this easier, the compiler can generate contract interface structs that expose a convenience method for each function listed in a given contract artifact. These structs are intended to be used from another contract project that calls into the current one. For each contract, two interface structs are generated: one to be used from private functions with a `PrivateContext`, and one to be used from open functions with a `PublicContext`. -To generate them, include a `--interface` option in the compile command with a path to the target folder for the generated Aztec.nr interface files: - -``` -aztec-cli compile --interface ./path/to/another_aztec_contract_project/src ./path/to/my_aztec_contract_project -``` - -You can also generate these interfaces from prebuilt artifacts using the `generate-noir-interface` command: +To generate them, include a `--nr` option in the `codegen` command with a path to the target folder for the generated Aztec.nr interface files: -``` -aztec-cli generate-noir-interface ./path/to/my_aztec_contract_project +```bash +aztec-cli codegen ./aztec-nargo/output/target/path -o ./path/to/output/folder --nr ``` Below is an example interface, also generated from the [Token](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/token_contract/src/main.nr) contract: diff --git a/yarn-project/cli/src/index.ts b/yarn-project/cli/src/index.ts index 2027ae779ff..7b108c9f724 100644 --- a/yarn-project/cli/src/index.ts +++ b/yarn-project/cli/src/index.ts @@ -1,9 +1,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { fileURLToPath } from '@aztec/foundation/url'; -import { - addGenerateNoirInterfaceCommanderAction, - addGenerateTypescriptCommanderAction, -} from '@aztec/noir-compiler/cli'; +import { addCodegenCommanderAction } from '@aztec/noir-compiler/cli'; import { Command, Option } from 'commander'; import { lookup } from 'dns/promises'; @@ -493,8 +490,7 @@ export function getProgram(log: LogFn, debugLogger: DebugLogger): Command { await update(projectPath, contract, rpcUrl, aztecVersion, log); }); - addGenerateTypescriptCommanderAction(program, log); - addGenerateNoirInterfaceCommanderAction(program, log); + addCodegenCommanderAction(program, log); return program; } diff --git a/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts b/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts index 5f8fb49236d..7c756965188 100644 --- a/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts +++ b/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts @@ -21,9 +21,7 @@ interface Options { * */ export function addNoirCompilerCommanderActions(program: Command, log: LogFn = () => {}) { - // addCompileCommanderAction(program, log); - addGenerateTypescriptCommanderAction(program, log); - addGenerateNoirInterfaceCommanderAction(program, log); + addCodegenCommanderAction(program, log); } /** @@ -48,30 +46,20 @@ export function addCompileCommanderAction(program: Command, log: LogFn = () => { /** * */ -export function addGenerateTypescriptCommanderAction(program: Command, _: LogFn = () => {}) { +export function addCodegenCommanderAction(program: Command, _: LogFn = () => {}) { program - .command('generate-typescript') + .command('codegen') .argument('', 'Path to the Noir ABI or project dir.') - .option('-o, --outdir ', 'Output folder for the generated typescript.') + .option('-o, --outdir ', 'Output folder for the generated code.') .option('-d, --debug', 'Include debug info.') - .description('Generates TypeScript interface from the given abi.') - .action(async (noirAbiPath: string, { debug, outdir }) => { - const { generateTypescriptInterface } = await import('./generate_typescript_interface.js'); - generateTypescriptInterface(outdir || dirname(noirAbiPath), noirAbiPath, debug); - }); -} - -/** - * - */ -export function addGenerateNoirInterfaceCommanderAction(program: Command, _: LogFn = () => {}) { - return program - .command('generate-noir-interface') - .argument('', 'Path to the Noir ABI or project dir.') - .option('-o, --outdir ', 'Output folder for the generated noir.') - .description('Generates Noir interfaces from the artifacts in the given project') - .action(async (noirAbiPath: string, { outdir }) => { - const { generateNoirInterface } = await import('./generate_noir_interface.js'); - generateNoirInterface(outdir || dirname(noirAbiPath), noirAbiPath); + .option('--ts', 'Generate TypeScript wrapper.') + .option('--nr', 'Generate Noir interface.') + .description('Validates and generates an Aztec Contract ABI from Noir ABI.') + .action(async (noirAbiPath: string, { debug, outdir, ts, nr }) => { + if (ts && nr) { + throw new Error('--ts and --nr are mutually exclusive.'); + } + const { generateCode } = await import('./codegen.js'); + generateCode(outdir || dirname(noirAbiPath), noirAbiPath, debug, ts, nr); }); } diff --git a/yarn-project/noir-compiler/src/cli/generate_typescript_interface.ts b/yarn-project/noir-compiler/src/cli/codegen.ts similarity index 62% rename from yarn-project/noir-compiler/src/cli/generate_typescript_interface.ts rename to yarn-project/noir-compiler/src/cli/codegen.ts index 08da2c63d68..98eb5670d42 100644 --- a/yarn-project/noir-compiler/src/cli/generate_typescript_interface.ts +++ b/yarn-project/noir-compiler/src/cli/codegen.ts @@ -3,36 +3,48 @@ import path from 'path'; import { generateContractArtifact } from '../contract-interface-gen/abi.js'; import { generateTypescriptContractInterface } from '../contract-interface-gen/contractTypescript.js'; +import { generateNoirContractInterface } from '../contract-interface-gen/noir.js'; /** * */ -export function generateTypescriptInterface(outputPath: string, fileOrDirPath: string, includeDebug = false) { +export function generateCode(outputPath: string, fileOrDirPath: string, includeDebug = false, ts = false, nr = false) { const stats = statSync(fileOrDirPath); if (stats.isDirectory()) { const files = readdirSync(fileOrDirPath).filter(file => file.endsWith('.json') && !file.startsWith('debug_')); for (const file of files) { const fullPath = path.join(fileOrDirPath, file); - generateTypescriptInterfaceFromNoirAbi(outputPath, fullPath, includeDebug); + generateFromNoirAbi(outputPath, fullPath, includeDebug, ts, nr); } } else if (stats.isFile()) { - generateTypescriptInterfaceFromNoirAbi(outputPath, fileOrDirPath, includeDebug); + generateFromNoirAbi(outputPath, fileOrDirPath, includeDebug, ts, nr); } } /** * */ -function generateTypescriptInterfaceFromNoirAbi(outputPath: string, noirAbiPath: string, includeDebug: boolean) { +function generateFromNoirAbi(outputPath: string, noirAbiPath: string, includeDebug: boolean, ts: boolean, nr: boolean) { const contract = JSON.parse(readFileSync(noirAbiPath, 'utf8')); const noirDebugPath = includeDebug ? getDebugFilePath(noirAbiPath) : undefined; const debug = noirDebugPath ? JSON.parse(readFileSync(noirDebugPath, 'utf8')) : undefined; const aztecAbi = generateContractArtifact({ contract, debug }); - const tsWrapper = generateTypescriptContractInterface(aztecAbi, `./${aztecAbi.name}.json`); + mkdirSync(outputPath, { recursive: true }); - writeFileSync(`${outputPath}/${aztecAbi.name}.ts`, tsWrapper); + + if (nr) { + const noirContract = generateNoirContractInterface(aztecAbi); + writeFileSync(`${outputPath}/${aztecAbi.name}.nr`, noirContract); + return; + } + writeFileSync(`${outputPath}/${aztecAbi.name}.json`, JSON.stringify(aztecAbi, undefined, 2)); + + if (ts) { + const tsWrapper = generateTypescriptContractInterface(aztecAbi, `./${aztecAbi.name}.json`); + writeFileSync(`${outputPath}/${aztecAbi.name}.ts`, tsWrapper); + } } /** diff --git a/yarn-project/noir-compiler/src/cli/generate_noir_interface.ts b/yarn-project/noir-compiler/src/cli/generate_noir_interface.ts deleted file mode 100644 index 268975ff034..00000000000 --- a/yarn-project/noir-compiler/src/cli/generate_noir_interface.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'fs'; -import path from 'path'; - -import { generateContractArtifact } from '../contract-interface-gen/abi.js'; -import { generateNoirContractInterface } from '../contract-interface-gen/noir.js'; - -/** - * - */ -export function generateNoirInterface(outputPath: string, fileOrDirPath: string) { - const stats = statSync(fileOrDirPath); - - if (stats.isDirectory()) { - const files = readdirSync(fileOrDirPath).filter(file => file.endsWith('.json') && !file.startsWith('debug_')); - for (const file of files) { - const fullPath = path.join(fileOrDirPath, file); - generateNoirInterfaceFromNoirAbi(outputPath, fullPath); - } - } else if (stats.isFile()) { - generateNoirInterfaceFromNoirAbi(outputPath, fileOrDirPath); - } -} - -/** - * - */ -export function generateNoirInterfaceFromNoirAbi(outputPath: string, noirAbiPath: string) { - const contract = JSON.parse(readFileSync(noirAbiPath, 'utf8')); - const aztecAbi = generateContractArtifact({ contract }); - const noirContract = generateNoirContractInterface(aztecAbi); - mkdirSync(outputPath, { recursive: true }); - writeFileSync(`${outputPath}/${aztecAbi.name}.nr`, noirContract); -} diff --git a/yarn-project/noir-contracts/scripts/generate-types.sh b/yarn-project/noir-contracts/scripts/generate-types.sh index a2e0b64b1fa..6901ab97f40 100755 --- a/yarn-project/noir-contracts/scripts/generate-types.sh +++ b/yarn-project/noir-contracts/scripts/generate-types.sh @@ -14,7 +14,7 @@ for ABI in $(find target -maxdepth 1 -type f ! -name 'debug_*' -name '*.json'); DEBUG_INFO="$(dirname $ABI)/debug_$(basename $ABI)" echo "Creating types for $CONTRACT in $ABI..." - node --no-warnings ../noir-compiler/dest/cli.js generate-typescript -o $OUT_DIR -d $ABI + node --no-warnings ../noir-compiler/dest/cli.js codegen -o $OUT_DIR -d --ts $ABI # Add contract import/export to index.ts. echo "export * from './${CONTRACT}.js';" >> $INDEX