diff --git a/.github/workflows/devnet-deploys.yml b/.github/workflows/devnet-deploys.yml index 75df1925cc8..b425c7330ca 100644 --- a/.github/workflows/devnet-deploys.yml +++ b/.github/workflows/devnet-deploys.yml @@ -58,13 +58,6 @@ jobs: const fileChanged = changedFiles.includes('l1-contracts/REDEPLOY'); return fileChanged - - name: "Build & Push cli image" - if: steps.check_changes_build.outputs.result == 'true' - timeout-minutes: 40 - # Run the build steps for each image with version and arch, push to dockerhub - run: | - earthly-ci --no-output --push ./yarn-project+export-cli --DIST_TAG=${{ env.DEPLOY_TAG }} - terraform_deploy: runs-on: ubuntu-latest needs: build @@ -97,8 +90,8 @@ jobs: - name: Deploy L1 Contracts if: steps.check_changes_release.outputs.result == 'true' run: | - docker pull aztecprotocol/cli:${{ env.DEPLOY_TAG }} - docker run aztecprotocol/cli:${{ env.DEPLOY_TAG }} \ + docker pull aztecprotocol/aztec:${{ env.DEPLOY_TAG }} + docker run aztecprotocol/aztec:${{ env.DEPLOY_TAG }} \ deploy-l1-contracts -p ${{ secrets.SEQ_1_PUBLISHER_PRIVATE_KEY }} \ -u https://${{ env.DEPLOY_TAG }}-mainnet-fork.aztec.network:8545/${{ secrets.FORK_API_KEY }} \ | tee ${{ env.FILE_PATH }} diff --git a/aztec-up/bin/aztec b/aztec-up/bin/aztec index a00575777c8..6f2ed002fa6 100755 --- a/aztec-up/bin/aztec +++ b/aztec-up/bin/aztec @@ -1,21 +1,39 @@ #!/usr/bin/env bash set -euo pipefail -# Call cli image if used with `aztec cli ...args` -if [ -n "${1-}" ] && [ "$1" != "--help" ]; then - if [ "$1" == "cli" ]; then - shift - SKIP_PORT_ASSIGNMENT=1 $(dirname $0)/.aztec-run aztecprotocol/cli "$@" - elif [ "$1" == "sandbox" ]; then - $(dirname $0)/aztec-sandbox - else - $(dirname $0)/.aztec-run aztecprotocol/aztec "$@" - fi -else - # TODO - display help message - echo - echo "Using 'aztec' CLI:" - echo " aztec start - Start aztec infrastructure components. See 'aztec start --help' for detailed command info." - echo " aztec sandbox - Run a local sandbox network (same as aztec-sandbox)." - echo " aztec cli - Run the aztec client CLI. See 'aztec cli --help' for detailed command info." +function get_compose { + # Favour 'docker compose', falling back on docker-compose. + CMD="docker compose" + $CMD &>/dev/null || CMD="docker-compose" + $CMD $@ +} + +CALLED_FROM=$PWD + +if [ "${1:-}" == "test" ]; then + # Change working dir, so relative volume mounts are in the right place. + cd $(dirname $0)/.. + # Compose file to use + FILE_ARG="-f $HOME/.aztec/docker-compose.test.yml" + # Aztec contract test args for nargo + TEST_ARGS="$@ --silence-warnings --use-legacy --oracle-resolver http://aztec:8081" + get_compose -p aztec-test $FILE_ARG run -e NARGO_FOREIGN_CALL_TIMEOUT=300000 --workdir $CALLED_FROM --rm -it aztec-nargo $TEST_ARGS +elif [ $# == 2 ] && [ "$1" == "start" ] && [ "$2" == "--sandbox" ]; then + # Change working dir, so relative volume mounts are in the right place. + cd $(dirname $0)/.. + # Compose file to use + FILE_ARG="-f $HOME/.aztec/docker-compose.sandbox.yml" + + # Function to be executed when SIGINT is received. + cleanup() { + get_compose $FILE_ARG down + } + + # Set trap to catch SIGINT and call the cleanup function. + trap cleanup SIGINT + + get_compose -p sandbox $FILE_ARG up --force-recreate --remove-orphans +else + $(dirname $0)/.aztec-run aztecprotocol/aztec "$@" fi + diff --git a/aztec-up/bin/aztec-builder b/aztec-up/bin/aztec-builder deleted file mode 100755 index c940ebf535e..00000000000 --- a/aztec-up/bin/aztec-builder +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -export SKIP_PORT_ASSIGNMENT=1 -export ENV_VARS_TO_INJECT="PXE_URL PRIVATE_KEY DEBUG" -export PXE_URL=${PXE_URL:-"http://host.docker.internal:8080"} -export ETHEREUM_HOST=${ETHEREUM_HOST:-"http://host.docker.internal:8545"} - -$(dirname $0)/.aztec-run aztecprotocol/aztec-builder $@ diff --git a/aztec-up/bin/aztec-install b/aztec-up/bin/aztec-install index 5a12629a917..310263be1fe 100755 --- a/aztec-up/bin/aztec-install +++ b/aztec-up/bin/aztec-install @@ -40,11 +40,9 @@ function title() { echo -e "${r}" fi echo -e "This will install the following scripts and update your PATH if necessary:" - echo -e " ${bold}${g}aztec${r} - launches various infrastructure subsystems (node, sequencer, prover, pxe, etc)." + echo -e " ${bold}${g}aztec${r} - a collection of tools to launch subsystems and interact with the aztec network." echo -e " ${bold}${g}aztec-nargo${r} - aztec's build of nargo, the noir compiler toolchain." - echo -e " ${bold}${g}aztec-sandbox${r} - a wrapper around docker-compose that launches services needed for sandbox testing." echo -e " ${bold}${g}aztec-up${r} - a tool to upgrade the aztec toolchain to the latest, or specific versions." - echo -e " ${bold}${g}aztec-builder${r} - a tool to generate typescript interfaces of Noir contracts" echo read -p "Do you wish to continue? (y/n)" -n 1 -r echo @@ -107,11 +105,11 @@ if [ -z "${SKIP_PULL:-}" ]; then info "Pulling aztec version $VERSION..." pull_container aztec-nargo pull_container aztec - pull_container aztec-builder fi # Download the Docker Compose file. Used by aztec. -curl -fsSL http://$INSTALL_HOST/docker-compose.yml -o $AZTEC_PATH/docker-compose.yml +curl -fsSL http://$INSTALL_HOST/docker-compose.sandbox.yml -o $AZTEC_PATH/docker-compose.sandbox.yml +curl -fsSL http://$INSTALL_HOST/docker-compose.test.yml -o $AZTEC_PATH/docker-compose.test.yml function install_bin { curl -fsSL http://$INSTALL_HOST/$1 -o $BIN_PATH/$1 @@ -123,10 +121,8 @@ info "Installing scripts in $BIN_PATH..." rm -f $BIN_PATH/aztec* install_bin .aztec-run install_bin aztec -install_bin aztec-sandbox install_bin aztec-up install_bin aztec-nargo -install_bin aztec-builder function update_path_env_var { TARGET_DIR="${1}" diff --git a/aztec-up/bin/aztec-sandbox b/aztec-up/bin/aztec-sandbox deleted file mode 100755 index 3d1f2d85953..00000000000 --- a/aztec-up/bin/aztec-sandbox +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Favour 'docker compose', falling back on docker-compose. -CMD="docker compose" -$CMD &>/dev/null || CMD="docker-compose" - -ARGS="-f $HOME/.aztec/docker-compose.yml -p sandbox" - -# Function to be executed when SIGINT is received. -cleanup() { - $CMD $ARGS down -} - -# Set trap to catch SIGINT and call the cleanup function. -trap cleanup SIGINT - -# Change working dir, so relative volume mounts are in the right place. -cd $(dirname $0)/.. - -$CMD $ARGS up --force-recreate --remove-orphans diff --git a/aztec-up/bin/docker-compose.yml b/aztec-up/bin/docker-compose.sandbox.yml similarity index 95% rename from aztec-up/bin/docker-compose.yml rename to aztec-up/bin/docker-compose.sandbox.yml index 775454fc2d0..2f856a751f0 100644 --- a/aztec-up/bin/docker-compose.yml +++ b/aztec-up/bin/docker-compose.sandbox.yml @@ -1,4 +1,3 @@ -version: "3" services: ethereum: image: ghcr.io/foundry-rs/foundry@sha256:29ba6e34379e79c342ec02d437beb7929c9e254261e8032b17e187be71a2609f @@ -36,3 +35,6 @@ services: TEST_ACCOUNTS: ${TEST_ACCOUNTS:-true} volumes: - ./log:/usr/src/yarn-project/aztec/log:rw + depends_on: + - ethereum + command: "start --sandbox" \ No newline at end of file diff --git a/aztec-up/bin/docker-compose.test.yml b/aztec-up/bin/docker-compose.test.yml new file mode 100644 index 00000000000..dca6d9f4435 --- /dev/null +++ b/aztec-up/bin/docker-compose.test.yml @@ -0,0 +1,19 @@ +services: + aztec: + image: "aztecprotocol/aztec" + environment: + DEBUG: # Loaded from the user shell if explicitly set + HOST_WORKDIR: "${PWD}" # Loaded from the user shell to show log files absolute path in host + volumes: + - ./log:/usr/src/yarn-project/aztec/log:rw + command: start --txe + + aztec-nargo: + image: "aztecprotocol/aztec-nargo" + environment: + HOME: # Loaded from the user shell + NARGO_FOREIGN_CALL_TIMEOUT: 300000 # To avoid timeouts when many tests run at once + volumes: + - ${HOME}:${HOME} + depends_on: + - aztec \ No newline at end of file diff --git a/barretenberg/acir_tests/headless-test/package.json b/barretenberg/acir_tests/headless-test/package.json index 43d976ee48a..7598d3275f8 100644 --- a/barretenberg/acir_tests/headless-test/package.json +++ b/barretenberg/acir_tests/headless-test/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "chalk": "^5.3.0", - "commander": "^12.0.0", + "commander": "^12.1.0", "playwright": "^1.42.1", "puppeteer": "^22.4.1" }, diff --git a/barretenberg/acir_tests/headless-test/src/index.ts b/barretenberg/acir_tests/headless-test/src/index.ts index bb906a6db2d..a318010c427 100644 --- a/barretenberg/acir_tests/headless-test/src/index.ts +++ b/barretenberg/acir_tests/headless-test/src/index.ts @@ -38,11 +38,13 @@ function formatAndPrintLog(message: string): void { } const readBytecodeFile = (path: string): Uint8Array => { - const extension = path.substring(path.lastIndexOf('.') + 1); + const extension = path.substring(path.lastIndexOf(".") + 1); - if (extension == 'json') { - const encodedCircuit = JSON.parse(fs.readFileSync(path, 'utf8')); - const decompressed = gunzipSync(Uint8Array.from(atob(encodedCircuit.bytecode), c => c.charCodeAt(0))); + if (extension == "json") { + const encodedCircuit = JSON.parse(fs.readFileSync(path, "utf8")); + const decompressed = gunzipSync( + Uint8Array.from(atob(encodedCircuit.bytecode), (c) => c.charCodeAt(0)) + ); return decompressed; } @@ -57,7 +59,7 @@ const readWitnessFile = (path: string): Uint8Array => { }; // Set up the command-line interface -const program = new Command(); +const program = new Command("headless_test"); program.option("-v, --verbose", "verbose logging"); program.option("-c, --crs-path ", "ignored (here for compatibility)"); @@ -84,7 +86,7 @@ program const browsers = { chrome: chromium, firefox: firefox, webkit: webkit }; for (const [name, browserType] of Object.entries(browsers)) { - if (BROWSER && !BROWSER.split(',').includes(name)) { + if (BROWSER && !BROWSER.split(",").includes(name)) { continue; } console.log(chalk.blue(`Testing ${bytecodePath} in ${name}...`)); diff --git a/barretenberg/ts/src/main.ts b/barretenberg/ts/src/main.ts index a3e17540fc6..2fe41eeebf8 100755 --- a/barretenberg/ts/src/main.ts +++ b/barretenberg/ts/src/main.ts @@ -419,7 +419,7 @@ export async function vkAsFieldsUltraHonk(vkPath: string, vkeyOutputPath: string } } -const program = new Command(); +const program = new Command('bb'); program.option('-v, --verbose', 'enable verbose logging', false); program.option('-c, --crs-path ', 'set crs path', './crs'); diff --git a/bootstrap.sh b/bootstrap.sh index 83216dc0470..a1c1a4b623d 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -6,6 +6,11 @@ # clean: Force a complete clean of the repo. Erases untracked files, be careful! set -eu +if [ "$(uname)" == "Darwin" ]; then + shopt -s expand_aliases + alias clang++-16="clang++" +fi + cd "$(dirname "$0")" CMD=${1:-} diff --git a/boxes/docker-compose.yml b/boxes/docker-compose.yml index b21036bb934..c42e6dbd5d2 100644 --- a/boxes/docker-compose.yml +++ b/boxes/docker-compose.yml @@ -6,6 +6,7 @@ services: aztec: image: aztecprotocol/aztec:${AZTEC_DOCKER_TAG:-latest} + command: 'start --sandbox' environment: ETHEREUM_HOST: http://ethereum:8545 CHAIN_ID: 31337 diff --git a/boxes/package.json b/boxes/package.json index 72690380907..7e5470a3c25 100644 --- a/boxes/package.json +++ b/boxes/package.json @@ -31,7 +31,7 @@ "@inquirer/input": "^2.0.0", "@inquirer/select": "^2.0.0", "axios": "^1.6.7", - "commander": "^12.0.0", + "commander": "^12.1.0", "ora": "^8.0.1", "pino": "^8.19.0", "pino-pretty": "^10.3.1", diff --git a/boxes/yarn.lock b/boxes/yarn.lock index 5a2e5e285d1..f23951cf713 100644 --- a/boxes/yarn.lock +++ b/boxes/yarn.lock @@ -2363,7 +2363,7 @@ __metadata: "@inquirer/select": "npm:^2.0.0" "@playwright/test": "npm:1.42.0" axios: "npm:^1.6.7" - commander: "npm:^12.0.0" + commander: "npm:^12.1.0" ora: "npm:^8.0.1" pino: "npm:^8.19.0" pino-pretty: "npm:^10.3.1" @@ -2966,10 +2966,10 @@ __metadata: languageName: node linkType: hard -"commander@npm:^12.0.0": - version: 12.0.0 - resolution: "commander@npm:12.0.0" - checksum: e51cac1d1d0aa1f76581981d2256a9249497e08f5a370bf63b0dfc7e76a647fc8cbc3ddd507928f2bdca6c514c83834e87e2687ace2fe2fc7cc7e631bf80f83d +"commander@npm:^12.1.0": + version: 12.1.0 + resolution: "commander@npm:12.1.0" + checksum: 6e1996680c083b3b897bfc1cfe1c58dfbcd9842fd43e1aaf8a795fbc237f65efcc860a3ef457b318e73f29a4f4a28f6403c3d653d021d960e4632dd45bde54a9 languageName: node linkType: hard diff --git a/docs/docs/guides/smart_contracts/testing_contracts/index.md b/docs/docs/guides/smart_contracts/testing_contracts/index.md index 1a4e5d5f0fc..acc6bf3baae 100644 --- a/docs/docs/guides/smart_contracts/testing_contracts/index.md +++ b/docs/docs/guides/smart_contracts/testing_contracts/index.md @@ -37,21 +37,14 @@ So to summarize: In order to use the TXE, it must be running on a known address. :::tip -If you have [the sandbox](../../../getting_started.md) installed, you can quickly deploy a TXE by running: +If you have [the sandbox](../../../getting_started.md) installed, you can run TXE tests using: -`docker run --workdir /usr/src/yarn-project --entrypoint bash --name txe -p 8080:8080 --rm -it aztecprotocol/aztec -c "yarn workspaces focus @aztec/txe && cd txe && yarn build && yarn start"` +`aztec test` -This will be improved in the future with a dedicated command. ::: -By default, TXE runs at `http://localhost:8080`. Using `aztec-nargo`, contract tests can be run with: - -`aztec-nargo test --use-legacy --silence-warnings --oracle-resolver http://host.docker.internal:8080` - :::warning Since TXE tests are written in Noir and executed with `aztec-nargo`, they all run in parallel. This also means every test creates their own isolated environment, so state modifications are local to each one of them. - -Executing many tests in parallel might slow processing of the RPC calls down to the point of making them timeout. To control this timeout the `NARGO_FOREIGN_CALL_TIMEOUT` env variable is used. ::: ### Writing TXE tests diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index af8d0bfcb2c..bb7057511ee 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -6,7 +6,24 @@ keywords: [sandbox, aztec, notes, migration, updating, upgrading] Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them. -## 0.45.0 +## 0.xx.0 +### [Aztec sandbox] Command refactor and unification + `aztec test` + +Sandbox commands have been cleaned up and simplified. Doing `aztec-up` now gets you the following top-level commands: + +`aztec`: All the previous commands + all the CLI ones without having to prefix them with cli. Run `aztec` for help! +`aztec-nargo`: No changes + +**REMOVED/RENAMED**: + +* `aztec-sandbox` and `aztec sandbox`: now `aztec start --sandbox` +* `aztec-builder`: now `aztec codegen` and `aztec update` + +**ADDED**: + +* `aztec test [options]`: runs `aztec start --txe && aztec-nargo test --use-legacy --oracle-resolver http://aztec:8081 --silence-warnings [options]` via docker-compose allowing users to easily run contract tests using TXE + +## 0.45.0 ### [Aztec.nr] Remove unencrypted logs from private They leak privacy so is a footgun! diff --git a/yarn-project/Earthfile b/yarn-project/Earthfile index 220f8292c8e..ae2c19e6551 100644 --- a/yarn-project/Earthfile +++ b/yarn-project/Earthfile @@ -185,37 +185,6 @@ export-aztec-faucet: ARG ARCH SAVE IMAGE --push aztecprotocol/aztec-faucet:${DIST_TAG}${ARCH:+-$ARCH} -cli-build: - FROM +build - RUN yarn workspaces focus @aztec/cli --production && yarn cache clean - RUN rm -rf \ - ../noir-projects \ - ../l1-contracts \ - ../barretenberg/ts/src \ - ../barretenberg/ts/dest/node-cjs \ - ../barretenberg/ts/dest/browser \ - aztec.js/dest/main.js \ - end-to-end \ - **/src \ - **/artifacts - SAVE ARTIFACT /usr/src /usr/src - -cli: - FROM ubuntu:noble - RUN apt update && apt install nodejs curl -y && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - COPY +cli-build/usr/src /usr/src - - RUN mkdir /cache && chmod 777 /cache - ENV XDG_CACHE_HOME /cache - VOLUME "/cache" - ENTRYPOINT ["node", "--no-warnings", "/usr/src/yarn-project/cli/dest/bin/index.js"] - -export-cli: - FROM +cli - ARG DIST_TAG="latest" - ARG ARCH - SAVE IMAGE --push aztecprotocol/cli:${DIST_TAG}${ARCH:+-$ARCH} - # We care about creating a slimmed down e2e image because we have to serialize it from earthly to docker for running. end-to-end-prod: FROM +build diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index d8a7831a0da..e8a8ba41297 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -35,6 +35,7 @@ "@aztec/builder": "workspace:^", "@aztec/circuit-types": "workspace:^", "@aztec/circuits.js": "workspace:^", + "@aztec/cli": "workspace:^", "@aztec/entrypoints": "workspace:^", "@aztec/ethereum": "workspace:^", "@aztec/foundation": "workspace:^", @@ -48,8 +49,9 @@ "@aztec/prover-client": "workspace:^", "@aztec/pxe": "workspace:^", "@aztec/telemetry-client": "workspace:^", + "@aztec/txe": "workspace:^", "abitype": "^0.8.11", - "commander": "^11.1.0", + "commander": "^12.1.0", "koa": "^2.14.2", "koa-router": "^12.0.0", "viem": "^2.7.15", diff --git a/yarn-project/aztec/src/aztec_client.ts b/yarn-project/aztec/src/aztec_client.ts deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/yarn-project/aztec/src/bin/index.ts b/yarn-project/aztec/src/bin/index.ts index 4cdc27c1798..5a2835bbfa4 100644 --- a/yarn-project/aztec/src/bin/index.ts +++ b/yarn-project/aztec/src/bin/index.ts @@ -1,64 +1,36 @@ -import { deployInitialTestAccounts } from '@aztec/accounts/testing'; -import { createAztecNodeRpcServer } from '@aztec/aztec-node'; import { fileURLToPath } from '@aztec/aztec.js'; -import { createNamespacedJsonRpcServer } from '@aztec/foundation/json-rpc/server'; +import { injectCommands as injectBuilderCommands } from '@aztec/cli/builder'; +import { injectCommands as injectContractCommands } from '@aztec/cli/contracts'; +import { injectCommands as injectInfrastructureCommands } from '@aztec/cli/infrastructure'; +import { injectCommands as injectL1Commands } from '@aztec/cli/l1'; +import { injectCommands as injectPXECommands } from '@aztec/cli/pxe'; +import { injectCommands as injectUtilsCommands } from '@aztec/cli/utils'; import { createConsoleLogger, createDebugLogger } from '@aztec/foundation/log'; -import { createPXERpcServer } from '@aztec/pxe'; +import { Command } from 'commander'; import { readFileSync } from 'fs'; -import http from 'http'; import { dirname, resolve } from 'path'; -import { getProgram } from '../cli/index.js'; -import { createAccountLogs, installSignalHandlers } from '../cli/util.js'; -import { createSandbox } from '../sandbox.js'; -import { github, splash } from '../splash.js'; +import { injectAztecCommands } from '../cli/index.js'; const userLog = createConsoleLogger(); const debugLogger = createDebugLogger('aztec:cli'); -const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json'); -const cliVersion: string = JSON.parse(readFileSync(packageJsonPath).toString()).version; - -const { TEST_ACCOUNTS = 'true', PORT = '8080', ENABLE_GAS = '' } = process.env; - /** CLI & full node main entrypoint */ async function main() { - if (process.argv.length > 2) { - // If CLI arguments were provided, run the CLI program. - const cliProgram = getProgram(userLog, debugLogger); - await cliProgram.parseAsync(process.argv); - } else { - // If no CLI arguments were provided, run aztec full node for sandbox usage. - userLog(`${splash}\n${github}\n\n`); - userLog(`Setting up Aztec Sandbox v${cliVersion}, please stand by...`); - const { aztecNodeConfig, node, pxe, stop } = await createSandbox({ - enableGas: ['true', '1'].includes(ENABLE_GAS), - }); - installSignalHandlers(userLog, [stop]); - - // Deploy test accounts by default - if (TEST_ACCOUNTS === 'true') { - if (aztecNodeConfig.p2pEnabled) { - userLog(`Not setting up test accounts as we are connecting to a network`); - } else { - userLog('Setting up test accounts...'); - const accounts = await deployInitialTestAccounts(pxe); - const accLogs = await createAccountLogs(accounts, pxe); - userLog(accLogs.join('')); - } - } - - // Start Node and PXE JSON-RPC server - const nodeServer = createAztecNodeRpcServer(node); - const pxeServer = createPXERpcServer(pxe); - const rpcServer = createNamespacedJsonRpcServer([{ node: nodeServer }, { pxe: pxeServer }], debugLogger); - - const app = rpcServer.getApp(); - const httpServer = http.createServer(app.callback()); - httpServer.listen(PORT); - userLog(`Aztec Server listening on port ${PORT}`); - } + const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json'); + const cliVersion: string = JSON.parse(readFileSync(packageJsonPath).toString()).version; + let program = new Command('aztec'); + program.description('Aztec command line interface').version(cliVersion); + program = injectAztecCommands(program, userLog, debugLogger); + program = injectBuilderCommands(program, userLog); + program = injectContractCommands(program, userLog, debugLogger); + program = injectInfrastructureCommands(program, userLog, debugLogger); + program = injectL1Commands(program, userLog, debugLogger); + program = injectPXECommands(program, userLog, debugLogger); + program = injectUtilsCommands(program, userLog); + + await program.parseAsync(process.argv); } main().catch(err => { diff --git a/yarn-project/aztec/src/cli/cli.ts b/yarn-project/aztec/src/cli/cli.ts index 87a4b6496ba..87595ed3b42 100644 --- a/yarn-project/aztec/src/cli/cli.ts +++ b/yarn-project/aztec/src/cli/cli.ts @@ -1,36 +1,32 @@ -import { fileURLToPath } from '@aztec/aztec.js'; +import { deployInitialTestAccounts } from '@aztec/accounts/testing'; +import { createAztecNodeRpcServer } from '@aztec/aztec-node'; import { type ServerList, createNamespacedJsonRpcServer, createStatusRouter } from '@aztec/foundation/json-rpc/server'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; +import { createPXERpcServer } from '@aztec/pxe'; -import { Command } from 'commander'; -import { readFileSync } from 'fs'; +import { type Command } from 'commander'; import http from 'http'; -import { dirname, resolve } from 'path'; +import { createSandbox } from '../sandbox.js'; +import { github, splash } from '../splash.js'; import { cliTexts } from './texts.js'; -import { installSignalHandlers } from './util.js'; +import { createAccountLogs, installSignalHandlers } from './util.js'; -const { AZTEC_PORT = '8080', API_PREFIX = '' } = process.env; +const { AZTEC_PORT = '8080', API_PREFIX = '', TEST_ACCOUNTS = 'true', ENABLE_GAS = '' } = process.env; /** * Returns commander program that defines the 'aztec' command line interface. * @param userLog - log function for logging user output. * @param debugLogger - logger for logging debug messages. */ -export function getProgram(userLog: LogFn, debugLogger: DebugLogger): Command { - const program = new Command(); - - const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json'); - const cliVersion: string = JSON.parse(readFileSync(packageJsonPath).toString()).version; - - program.name('aztec').description('Aztec command line interface').version(cliVersion); - +export function injectAztecCommands(program: Command, userLog: LogFn, debugLogger: DebugLogger) { // Start Aztec modules with options program .command('start') .description( 'Starts Aztec modules. Options for each module can be set as key-value pairs (e.g. "option1=value1,option2=value2") or as environment variables.', ) + .option('-sb, --sandbox', 'Starts Aztec Sandbox.') .option('-p, --port ', 'Port to run Aztec on.', AZTEC_PORT) .option('-n, --node [options]', cliTexts.node) .option('-px, --pxe [options]', cliTexts.pxe) @@ -38,28 +34,61 @@ export function getProgram(userLog: LogFn, debugLogger: DebugLogger): Command { .option('-s, --sequencer [options]', cliTexts.sequencer) .option('-r, --prover [options]', cliTexts.prover) .option('-p2p, --p2p-bootstrap [options]', cliTexts.p2pBootstrap) + .option('-t, --txe [options]', cliTexts.txe) .action(async options => { // list of 'stop' functions to call when process ends const signalHandlers: Array<() => Promise> = []; let services: ServerList = []; - // Start Aztec Node - if (options.node) { - const { startNode } = await import('./cmds/start_node.js'); - services = await startNode(options, signalHandlers, userLog); - } else if (options.pxe) { - const { startPXE } = await import('./cmds/start_pxe.js'); - services = await startPXE(options, signalHandlers, userLog); - } else if (options.archiver) { - const { startArchiver } = await import('./cmds/start_archiver.js'); - services = await startArchiver(options, signalHandlers); - } else if (options.p2pBootstrap) { - const { startP2PBootstrap } = await import('./cmds/start_p2p_bootstrap.js'); - await startP2PBootstrap(options, userLog, debugLogger); - } else if (options.prover) { - const { startProver } = await import('./cmds/start_prover.js'); - services = await startProver(options, signalHandlers, userLog); + if (options.sandbox) { + // If no CLI arguments were provided, run aztec full node for sandbox usage. + userLog(`${splash}\n${github}\n\n`); + userLog(`Setting up Aztec Sandbox, please stand by...`); + const { aztecNodeConfig, node, pxe, stop } = await createSandbox({ + enableGas: ['true', '1'].includes(ENABLE_GAS), + }); + + // Deploy test accounts by default + if (TEST_ACCOUNTS === 'true') { + if (aztecNodeConfig.p2pEnabled) { + userLog(`Not setting up test accounts as we are connecting to a network`); + } else { + userLog('Setting up test accounts...'); + const accounts = await deployInitialTestAccounts(pxe); + const accLogs = await createAccountLogs(accounts, pxe); + userLog(accLogs.join('')); + } + } + + // Start Node and PXE JSON-RPC server + const nodeServer = createAztecNodeRpcServer(node); + const pxeServer = createPXERpcServer(pxe); + signalHandlers.push(stop); + services = [{ node: nodeServer }, { pxe: pxeServer }]; + } else { + // Start Aztec Node + if (options.node) { + const { startNode } = await import('./cmds/start_node.js'); + services = await startNode(options, signalHandlers, userLog); + } else if (options.pxe) { + const { startPXE } = await import('./cmds/start_pxe.js'); + services = await startPXE(options, signalHandlers, userLog); + } else if (options.archiver) { + const { startArchiver } = await import('./cmds/start_archiver.js'); + services = await startArchiver(options, signalHandlers); + } else if (options.p2pBootstrap) { + const { startP2PBootstrap } = await import('./cmds/start_p2p_bootstrap.js'); + await startP2PBootstrap(options, userLog, debugLogger); + } else if (options.prover) { + const { startProver } = await import('./cmds/start_prover.js'); + services = await startProver(options, signalHandlers, userLog); + } else if (options.txe) { + const { startTXE } = await import('./cmds/start_txe.js'); + startTXE(options, debugLogger); + } } + installSignalHandlers(debugLogger.info, signalHandlers); + if (services.length) { const rpcServer = createNamespacedJsonRpcServer(services, debugLogger); @@ -72,7 +101,22 @@ export function getProgram(userLog: LogFn, debugLogger: DebugLogger): Command { httpServer.listen(options.port); userLog(`Aztec Server listening on port ${options.port}`); } - installSignalHandlers(debugLogger.info, signalHandlers); }); + + program.configureHelp({ sortSubcommands: true }); + + program.addHelpText( + 'after', + ` + + Additional commands: + + test [options]: starts a dockerized TXE node via + $ aztec start --txe + then runs + $ aztec-nargo test --silence-warnings --use-legacy --oracle-resolver= [options] + `, + ); + return program; } diff --git a/yarn-project/aztec/src/cli/cmds/start_txe.ts b/yarn-project/aztec/src/cli/cmds/start_txe.ts new file mode 100644 index 00000000000..c1d172df57f --- /dev/null +++ b/yarn-project/aztec/src/cli/cmds/start_txe.ts @@ -0,0 +1,17 @@ +import { type DebugLogger } from '@aztec/foundation/log'; +import { createTXERpcServer } from '@aztec/txe'; + +import http from 'http'; + +const { TXE_PORT = 8081 } = process.env; + +export const startTXE = (options: any, debugLogger: DebugLogger) => { + debugLogger.info(`Setting up TXE...`); + const txeServer = createTXERpcServer(debugLogger); + const app = txeServer.getApp(); + const httpServer = http.createServer(app.callback()); + httpServer.timeout = 1e3 * 60 * 5; // 5 minutes + const port = parseInt(options.txePort || TXE_PORT, 10); + httpServer.listen(port); + debugLogger.info(`TXE listening on port ${port}`); +}; diff --git a/yarn-project/aztec/src/cli/texts.ts b/yarn-project/aztec/src/cli/texts.ts index b7f9abdc1fa..e3a677dfd9c 100644 --- a/yarn-project/aztec/src/cli/texts.ts +++ b/yarn-project/aztec/src/cli/texts.ts @@ -81,4 +81,8 @@ export const cliTexts = { 'Starts a P2P bootstrap node with options.\n' + 'Available options are listed below as cliProperty:ENV_VARIABLE_NAME.\n' + p2pOptions, + txe: + 'Starts a TXE with options\n' + + 'Available options are listed below as cliProperty:ENV_VARIABLE_NAME.\n' + + 'txePort:TXE_PORT - number - The port on which the TXE should listen for connections. Default: 8081\n', }; diff --git a/yarn-project/aztec/tsconfig.json b/yarn-project/aztec/tsconfig.json index 61805f56d7a..e738c2ced35 100644 --- a/yarn-project/aztec/tsconfig.json +++ b/yarn-project/aztec/tsconfig.json @@ -30,6 +30,9 @@ { "path": "../circuits.js" }, + { + "path": "../cli" + }, { "path": "../entrypoints" }, @@ -68,6 +71,9 @@ }, { "path": "../telemetry-client" + }, + { + "path": "../txe" } ], "include": ["src"] diff --git a/yarn-project/bb-prover/package.json b/yarn-project/bb-prover/package.json index 909ffa5251a..37030d36b12 100644 --- a/yarn-project/bb-prover/package.json +++ b/yarn-project/bb-prover/package.json @@ -68,7 +68,7 @@ "@msgpack/msgpack": "^3.0.0-beta2", "@noir-lang/noirc_abi": "portal:../../noir/packages/noirc_abi", "@noir-lang/types": "portal:../../noir/packages/types", - "commander": "^9.0.0", + "commander": "^12.1.0", "source-map-support": "^0.5.21", "tslib": "^2.4.0" }, diff --git a/yarn-project/bb-prover/src/bb/cli.ts b/yarn-project/bb-prover/src/bb/cli.ts index ae585b37797..ca26dabb535 100644 --- a/yarn-project/bb-prover/src/bb/cli.ts +++ b/yarn-project/bb-prover/src/bb/cli.ts @@ -14,9 +14,9 @@ const { BB_WORKING_DIRECTORY, BB_BINARY_PATH } = process.env; * @returns The CLI. */ export function getProgram(log: LogFn): Command { - const program = new Command(); + const program = new Command('bb-cli'); - program.name('bb-cli').description('CLI for interacting with Barretenberg.'); + program.description('CLI for interacting with Barretenberg.'); program .command('protocol-circuits') @@ -89,38 +89,6 @@ export function getProgram(log: LogFn): Command { ); }); - program - .command('write-vk') - .description('Generates the verification key for the specified circuit') - .requiredOption( - '-w, --working-directory ', - 'A directory to use for storing input/output files', - BB_WORKING_DIRECTORY, - ) - .requiredOption('-b, --bb-path ', 'The path to the BB binary', BB_BINARY_PATH) - .requiredOption('-c, --circuit ', 'The name of a protocol circuit') - .action(async options => { - const compiledCircuit = ProtocolCircuitArtifacts[options.circuit as ProtocolArtifact]; - if (!compiledCircuit) { - log(`Failed to find circuit ${options.circuit}`); - return; - } - try { - await fs.access(options.workingDirectory, fs.constants.W_OK); - } catch (error) { - log(`Working directory does not exist`); - return; - } - await generateKeyForNoirCircuit( - options.bbPath, - options.workingDirectory, - options.circuit, - compiledCircuit, - 'vk', - log, - ); - }); - program .command('write-contract') .description('Generates the verification contract for the specified circuit') diff --git a/yarn-project/builder/package.json b/yarn-project/builder/package.json index c6f153b7f05..a94c6252f89 100644 --- a/yarn-project/builder/package.json +++ b/yarn-project/builder/package.json @@ -65,30 +65,14 @@ ] }, "dependencies": { - "@aztec/circuits.js": "workspace:^", + "@aztec/cli": "workspace:^", "@aztec/foundation": "workspace:^", - "@aztec/types": "workspace:^", - "@iarna/toml": "^2.2.5", - "base64-js": "^1.5.1", - "commander": "^9.0.0", - "fs-extra": "^11.1.1", - "lodash.camelcase": "^4.3.0", - "lodash.capitalize": "^4.2.1", - "memfs": "^4.6.0", - "pako": "^2.1.0", - "semver": "^7.5.4", - "tslib": "^2.4.0", - "unzipit": "^1.4.3" + "commander": "^12.1.0" }, "devDependencies": { "@jest/globals": "^29.5.0", - "@types/fs-extra": "^11.0.1", "@types/jest": "^29.5.0", - "@types/lodash.camelcase": "^4.3.7", - "@types/lodash.capitalize": "^4.2.7", "@types/node": "^18.7.23", - "@types/pako": "^2.0.0", - "@types/semver": "^7.5.4", "jest": "^29.5.0", "ts-node": "^10.9.1", "typescript": "^5.0.4" diff --git a/yarn-project/builder/src/cli.ts b/yarn-project/builder/src/cli.ts index 9dea06bba50..0bbe358b53f 100644 --- a/yarn-project/builder/src/cli.ts +++ b/yarn-project/builder/src/cli.ts @@ -1,37 +1,15 @@ #!/usr/bin/env node +import { injectCommands as injectBuilderCommands } from '@aztec/cli/builder'; import { createConsoleLogger } from '@aztec/foundation/log'; import { Command } from 'commander'; -import { dirname } from 'path'; -const program = new Command(); const log = createConsoleLogger('aztec:builder'); const main = async () => { - program.name('aztec-builder'); - program - .command('codegen') - .argument('', 'Path to the Noir ABI or project dir.') - .option('-o, --outdir ', 'Output folder for the generated code.') - .option('--force', 'Force code generation even when the contract has not changed.') - .description('Validates and generates an Aztec Contract ABI from Noir ABI.') - .action(async (noirAbiPath: string, { outdir, force }) => { - const { generateCode } = await import('./cli/codegen.js'); - generateCode(outdir || dirname(noirAbiPath), noirAbiPath, { force }); - }); - - program - .command('update') - .description('Updates Nodejs and Noir dependencies') - .argument('[projectPath]', 'Path to the project directory', process.cwd()) - .option('--contract [paths...]', 'Paths to contracts to update dependencies', []) - .option('--aztec-version ', 'The version to update Aztec packages to. Defaults to latest', 'latest') - .action(async (projectPath: string, options) => { - const { update } = await import('./cli/update/update.js'); - const { contract, aztecVersion } = options; - await update(projectPath, contract, aztecVersion, log); - }); + const program = new Command('aztec-builder'); + injectBuilderCommands(program, log); await program.parseAsync(process.argv); // I force exit here because spawnSync in npm.ts just blocks the process from exiting. Spent a bit of time debugging // it without success and I think it doesn't make sense to invest more time in this. diff --git a/yarn-project/builder/src/index.ts b/yarn-project/builder/src/index.ts deleted file mode 100644 index c6c4a84e441..00000000000 --- a/yarn-project/builder/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { generateTypescriptContractInterface } from './contract-interface-gen/typescript.js'; diff --git a/yarn-project/builder/src/mocked_keys.ts b/yarn-project/builder/src/mocked_keys.ts deleted file mode 100644 index b8f5c677ead..00000000000 --- a/yarn-project/builder/src/mocked_keys.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const mockVerificationKey = - '0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f'; diff --git a/yarn-project/builder/src/utils.ts b/yarn-project/builder/src/utils.ts deleted file mode 100644 index 6a097708b01..00000000000 --- a/yarn-project/builder/src/utils.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { type ContractArtifact } from '@aztec/foundation/abi'; - -/** - * Checks if the given input looks like a valid ContractArtifact. The check is not exhaustive, - * and it's just meant to differentiate between nargo raw build artifacts and the ones - * produced by this compiler. - * @param input - Input object. - * @returns True if it looks like a ContractArtifact. - */ -export function isContractArtifact(input: any): input is ContractArtifact { - if (typeof input !== 'object') { - return false; - } - const maybeContractArtifact = input as ContractArtifact; - if (typeof maybeContractArtifact.name !== 'string') { - return false; - } - if (!Array.isArray(maybeContractArtifact.functions)) { - return false; - } - for (const fn of maybeContractArtifact.functions) { - if (typeof fn.name !== 'string') { - return false; - } - if (typeof fn.functionType !== 'string') { - return false; - } - if (typeof fn.isInternal !== 'boolean') { - return false; - } - } - return true; -} diff --git a/yarn-project/builder/tsconfig.json b/yarn-project/builder/tsconfig.json index 00bc12a18a0..471eb519c82 100644 --- a/yarn-project/builder/tsconfig.json +++ b/yarn-project/builder/tsconfig.json @@ -7,13 +7,10 @@ }, "references": [ { - "path": "../circuits.js" + "path": "../cli" }, { "path": "../foundation" - }, - { - "path": "../types" } ], "include": ["src", "src/*.json"] diff --git a/yarn-project/cli/Dockerfile b/yarn-project/cli/Dockerfile deleted file mode 100644 index c69606b278c..00000000000 --- a/yarn-project/cli/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM aztecprotocol/yarn-project AS yarn-project -ENTRYPOINT ["node", "--no-warnings", "/usr/src/yarn-project/cli/dest/bin/index.js"] - -# The version has been updated in yarn-project. -# Adding COMMIT_TAG here to rebuild versioned image. -ARG COMMIT_TAG="" - -RUN mkdir /cache && chmod 777 /cache -ENV XDG_CACHE_HOME /cache -VOLUME "/cache" diff --git a/yarn-project/cli/aztec-cli-dest b/yarn-project/cli/aztec-cli-dest deleted file mode 100755 index d2fc2aa3694..00000000000 --- a/yarn-project/cli/aztec-cli-dest +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -SCRIPT_PATH=$(dirname $(realpath $0)) -node --no-warnings $SCRIPT_PATH/dest/bin/index.js $@ diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index 34b2c2a91b9..cb1ada4c7f0 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -2,13 +2,17 @@ "name": "@aztec/cli", "version": "0.32.0", "type": "module", - "main": "./dest/index.js", - "bin": { - "aztec-cli": "./dest/bin/index.js" + "exports": { + "./builder": "./dest/cmds/builder/index.js", + "./contracts": "./dest/cmds/contracts/index.js", + "./infrastructure": "./dest/cmds/infrastructure/index.js", + "./l1": "./dest/cmds/l1/index.js", + "./pxe": "./dest/cmds/pxe/index.js", + "./utils": "./dest/cmds/utils/index.js" }, "typedocOptions": { "entryPoints": [ - "./src/index.ts" + "./dest/builder/index.js" ], "name": "Aztec CLI", "tsconfig": "./tsconfig.json" @@ -19,8 +23,7 @@ "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", - "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests", - "start": "yarn build && node --no-warnings ./dest/bin/index.js" + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests" }, "inherits": [ "../package.common.json" @@ -58,26 +61,14 @@ ] }, "dependencies": { - "@aztec/accounts": "workspace:^", "@aztec/aztec.js": "workspace:^", - "@aztec/bb-prover": "workspace:^", "@aztec/circuit-types": "workspace:^", - "@aztec/circuits.js": "workspace:^", - "@aztec/ethereum": "workspace:^", "@aztec/foundation": "workspace:^", - "@aztec/l1-artifacts": "workspace:^", - "@aztec/noir-contracts.js": "workspace:^", - "@aztec/noir-protocol-circuits-types": "workspace:^", - "@aztec/protocol-contracts": "workspace:^", - "@aztec/simulator": "workspace:^", "@aztec/types": "workspace:^", "@iarna/toml": "^2.2.5", "@libp2p/peer-id-factory": "^3.0.4", "axios": "^1.7.2", - "commander": "^9.0.0", - "jszip": "^3.10.1", - "lodash.startcase": "^4.4.0", - "node-fetch": "^3.3.2", + "commander": "^12.1.0", "semver": "^7.5.4", "solc": "^0.8.26", "source-map-support": "^0.5.21", @@ -85,6 +76,11 @@ "viem": "^2.7.15" }, "devDependencies": { + "@aztec/accounts": "workspace:^", + "@aztec/circuits.js": "workspace:^", + "@aztec/ethereum": "workspace:^", + "@aztec/l1-artifacts": "workspace:^", + "@aztec/protocol-contracts": "workspace:^", "@jest/globals": "^29.5.0", "@types/jest": "^29.5.0", "@types/lodash.startcase": "^4.4.7", @@ -97,6 +93,16 @@ "ts-node": "^10.9.1", "typescript": "^5.0.4" }, + "peerDependencies": { + "@aztec/accounts": "workspace:^", + "@aztec/bb-prover": "workspace:^", + "@aztec/circuits.js": "workspace:^", + "@aztec/ethereum": "workspace:^", + "@aztec/l1-artifacts": "workspace:^", + "@aztec/noir-contracts.js": "workspace:^", + "@aztec/noir-protocol-circuits-types": "workspace:^", + "@aztec/protocol-contracts": "workspace:^" + }, "files": [ "dest", "src", diff --git a/yarn-project/cli/src/bin/index.ts b/yarn-project/cli/src/bin/index.ts deleted file mode 100644 index 0d79e796d50..00000000000 --- a/yarn-project/cli/src/bin/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env -S node --no-warnings -import { createConsoleLogger, createDebugLogger } from '@aztec/foundation/log'; - -import 'source-map-support/register.js'; - -import { getProgram } from '../index.js'; - -const debugLogger = createDebugLogger('aztec:cli-client'); -const log = createConsoleLogger(); - -/** CLI main entrypoint */ -async function main() { - process.once('SIGINT', () => process.exit(0)); - process.once('SIGTERM', () => process.exit(0)); - - const program = getProgram(log, debugLogger); - await program.parseAsync(process.argv); -} - -main().catch(err => { - log(`Error in command execution`); - log(err); - process.exit(1); -}); diff --git a/yarn-project/cli/src/cmds/add_pending_shield.ts b/yarn-project/cli/src/cmds/add_pending_shield.ts deleted file mode 100644 index 1ae6f4f9da1..00000000000 --- a/yarn-project/cli/src/cmds/add_pending_shield.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { type AztecAddress, Fr, computeSecretHash } from '@aztec/aztec.js'; -import { ExtendedNote, Note, type TxHash } from '@aztec/circuit-types'; -import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { TokenContract } from '@aztec/noir-contracts.js'; - -import { createCompatibleClient } from '../client.js'; - -export async function addPendingShield( - ownerAddress: AztecAddress, - tokenAddress: AztecAddress, - amount: bigint, - secret: Fr, - txHash: TxHash, - rpcUrl: string, - debugLogger: DebugLogger, - log: LogFn, -) { - const secretHash = computeSecretHash(secret); - const note = new Note([new Fr(amount), secretHash]); - const extendedNote = new ExtendedNote( - note, - ownerAddress, - tokenAddress, - TokenContract.storage.pending_shields.slot, - TokenContract.notes.TransparentNote.id, - txHash, - ); - const client = await createCompatibleClient(rpcUrl, debugLogger); - await client.addNote(extendedNote); - log(`Added pending shield note owned by ${ownerAddress.toString()} for ${amount}`); -} - -// await t.addPendingShieldNoteToPXE(bobsAddress, maxFee - actualFee, computeSecretHash(rebateSecret), tx.txHash); diff --git a/yarn-project/cli/src/cmds/builder/codegen.ts b/yarn-project/cli/src/cmds/builder/codegen.ts new file mode 100644 index 00000000000..d721b5da63e --- /dev/null +++ b/yarn-project/cli/src/cmds/builder/codegen.ts @@ -0,0 +1,8 @@ +import { type GenerateCodeOptions, generateCode } from './contract-interface-gen/codegen.js'; + +/** + * Generates Noir interface or Typescript interface for a folder or single file from a Noir compilation artifact. + */ +export function codegen(outputPath: string, fileOrDirPath: string, opts: GenerateCodeOptions = {}) { + generateCode(outputPath, fileOrDirPath, opts); +} diff --git a/yarn-project/builder/src/cli/codegen.ts b/yarn-project/cli/src/cmds/builder/contract-interface-gen/codegen.ts similarity index 95% rename from yarn-project/builder/src/cli/codegen.ts rename to yarn-project/cli/src/cmds/builder/contract-interface-gen/codegen.ts index 858109a982b..4f40886f42a 100644 --- a/yarn-project/builder/src/cli/codegen.ts +++ b/yarn-project/cli/src/cmds/builder/contract-interface-gen/codegen.ts @@ -5,13 +5,13 @@ import crypto from 'crypto'; import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'fs'; import path from 'path'; -import { generateTypescriptContractInterface } from '../contract-interface-gen/typescript.js'; +import { generateTypescriptContractInterface } from './typescript.js'; const cacheFilePath = './codegenCache.json'; let cache: Record = {}; /** Generate code options */ -type GenerateCodeOptions = { force?: boolean }; +export type GenerateCodeOptions = { force?: boolean }; /** * Generates Noir interface or Typescript interface for a folder or single file from a Noir compilation artifact. diff --git a/yarn-project/builder/src/contract-interface-gen/typescript.ts b/yarn-project/cli/src/cmds/builder/contract-interface-gen/typescript.ts similarity index 100% rename from yarn-project/builder/src/contract-interface-gen/typescript.ts rename to yarn-project/cli/src/cmds/builder/contract-interface-gen/typescript.ts diff --git a/yarn-project/cli/src/cmds/builder/index.ts b/yarn-project/cli/src/cmds/builder/index.ts new file mode 100644 index 00000000000..971a63a22a5 --- /dev/null +++ b/yarn-project/cli/src/cmds/builder/index.ts @@ -0,0 +1,30 @@ +import { type LogFn } from '@aztec/foundation/log'; + +import { type Command } from 'commander'; +import { dirname } from 'path'; + +export function injectCommands(program: Command, log: LogFn) { + program + .command('codegen') + .argument('', 'Path to the Noir ABI or project dir.') + .option('-o, --outdir ', 'Output folder for the generated code.') + .option('--force', 'Force code generation even when the contract has not changed.') + .description('Validates and generates an Aztec Contract ABI from Noir ABI.') + .action(async (noirAbiPath: string, { outdir, force }) => { + const { codegen } = await import('./codegen.js'); + codegen(outdir || dirname(noirAbiPath), noirAbiPath, { force }); + }); + + program + .command('update') + .description('Updates Nodejs and Noir dependencies') + .argument('[projectPath]', 'Path to the project directory', process.cwd()) + .option('--contract [paths...]', 'Paths to contracts to update dependencies', []) + .option('--aztec-version ', 'The version to update Aztec packages to. Defaults to latest', 'latest') + .action(async (projectPath: string, options) => { + const { updateProject } = await import('./update.js'); + const { contract, aztecVersion } = options; + await updateProject(projectPath, contract, aztecVersion, log); + }); + return program; +} diff --git a/yarn-project/builder/src/cli/update/update.ts b/yarn-project/cli/src/cmds/builder/update.ts similarity index 90% rename from yarn-project/builder/src/cli/update/update.ts rename to yarn-project/cli/src/cmds/builder/update.ts index 5d518839ebb..fa8265e425c 100644 --- a/yarn-project/builder/src/cli/update/update.ts +++ b/yarn-project/cli/src/cmds/builder/update.ts @@ -4,15 +4,15 @@ import { type LogFn } from '@aztec/foundation/log'; import { relative, resolve } from 'path'; import { parse } from 'semver'; -import { type DependencyChanges } from './common.js'; -import { GITHUB_TAG_PREFIX } from './github.js'; -import { updateAztecNr } from './noir.js'; -import { getNewestVersion, updateAztecDeps, updateLockfile } from './npm.js'; +import { type DependencyChanges } from './update/common.js'; +import { GITHUB_TAG_PREFIX } from './update/github.js'; +import { updateAztecNr } from './update/noir.js'; +import { getNewestVersion, updateAztecDeps, updateLockfile } from './update/npm.js'; const AZTECJS_PACKAGE = '@aztec/aztec.js'; const UPDATE_DOCS_URL = 'https://docs.aztec.network/developers/updating'; -export async function update( +export async function updateProject( projectPath: string, contracts: string[], aztecVersion: string, diff --git a/yarn-project/builder/src/cli/update/common.ts b/yarn-project/cli/src/cmds/builder/update/common.ts similarity index 100% rename from yarn-project/builder/src/cli/update/common.ts rename to yarn-project/cli/src/cmds/builder/update/common.ts diff --git a/yarn-project/builder/src/cli/update/github.ts b/yarn-project/cli/src/cmds/builder/update/github.ts similarity index 100% rename from yarn-project/builder/src/cli/update/github.ts rename to yarn-project/cli/src/cmds/builder/update/github.ts diff --git a/yarn-project/builder/src/cli/update/noir.ts b/yarn-project/cli/src/cmds/builder/update/noir.ts similarity index 100% rename from yarn-project/builder/src/cli/update/noir.ts rename to yarn-project/cli/src/cmds/builder/update/noir.ts diff --git a/yarn-project/builder/src/cli/update/npm.ts b/yarn-project/cli/src/cmds/builder/update/npm.ts similarity index 100% rename from yarn-project/builder/src/cli/update/npm.ts rename to yarn-project/cli/src/cmds/builder/update/npm.ts diff --git a/yarn-project/builder/src/cli/update/utils.ts b/yarn-project/cli/src/cmds/builder/update/utils.ts similarity index 100% rename from yarn-project/builder/src/cli/update/utils.ts rename to yarn-project/cli/src/cmds/builder/update/utils.ts diff --git a/yarn-project/cli/src/cmds/contracts/index.ts b/yarn-project/cli/src/cmds/contracts/index.ts new file mode 100644 index 00000000000..368151c92a0 --- /dev/null +++ b/yarn-project/cli/src/cmds/contracts/index.ts @@ -0,0 +1,34 @@ +import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; + +import { type Command } from 'commander'; + +export function injectCommands(program: Command, log: LogFn, debugLogger: DebugLogger) { + program + .command('inspect-contract') + .description('Shows list of external callable functions for a contract') + .argument( + '', + `A compiled Noir contract's artifact in JSON format or name of a contract artifact exported by @aztec/noir-contracts.js`, + ) + .action(async (contractArtifactFile: string) => { + const { inspectContract } = await import('./inspect_contract.js'); + await inspectContract(contractArtifactFile, debugLogger, log); + }); + + // Helper for users to decode hex strings into structs if needed. + program + .command('parse-parameter-struct') + .description("Helper for parsing an encoded string into a contract's parameter struct.") + .argument('', 'The encoded hex string') + .requiredOption( + '-c, --contract-artifact ', + "A compiled Aztec.nr contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts.js", + ) + .requiredOption('-p, --parameter ', 'The name of the struct parameter to decode into') + .action(async (encodedString, options) => { + const { parseParameterStruct } = await import('./parse_parameter_struct.js'); + await parseParameterStruct(encodedString, options.contractArtifact, options.parameter, log); + }); + + return program; +} diff --git a/yarn-project/cli/src/cmds/inspect_contract.ts b/yarn-project/cli/src/cmds/contracts/inspect_contract.ts similarity index 97% rename from yarn-project/cli/src/cmds/inspect_contract.ts rename to yarn-project/cli/src/cmds/contracts/inspect_contract.ts index 09284f3abe8..7274141cc2f 100644 --- a/yarn-project/cli/src/cmds/inspect_contract.ts +++ b/yarn-project/cli/src/cmds/contracts/inspect_contract.ts @@ -8,7 +8,7 @@ import { import { sha256 } from '@aztec/foundation/crypto'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { getContractArtifact } from '../utils.js'; +import { getContractArtifact } from '../../utils/aztec.js'; export async function inspectContract(contractArtifactFile: string, debugLogger: DebugLogger, log: LogFn) { const contractArtifact = await getContractArtifact(contractArtifactFile, log); diff --git a/yarn-project/cli/src/cmds/parse_parameter_struct.ts b/yarn-project/cli/src/cmds/contracts/parse_parameter_struct.ts similarity index 87% rename from yarn-project/cli/src/cmds/parse_parameter_struct.ts rename to yarn-project/cli/src/cmds/contracts/parse_parameter_struct.ts index 15bc057ede9..016c08ad468 100644 --- a/yarn-project/cli/src/cmds/parse_parameter_struct.ts +++ b/yarn-project/cli/src/cmds/contracts/parse_parameter_struct.ts @@ -2,8 +2,8 @@ import { type StructType } from '@aztec/foundation/abi'; import { JsonStringify } from '@aztec/foundation/json-rpc'; import { type LogFn } from '@aztec/foundation/log'; -import { parseStructString } from '../encoding.js'; -import { getContractArtifact } from '../utils.js'; +import { parseStructString } from '../../encoding.js'; +import { getContractArtifact } from '../../utils/aztec.js'; export async function parseParameterStruct( encodedString: string, diff --git a/yarn-project/cli/src/cmds/get_balance.ts b/yarn-project/cli/src/cmds/get_balance.ts deleted file mode 100644 index 4fa7d7f5cc3..00000000000 --- a/yarn-project/cli/src/cmds/get_balance.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { AztecAddress } from '@aztec/aztec.js'; -import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { TokenContractArtifact } from '@aztec/noir-contracts.js'; -import { GasTokenAddress, GasTokenArtifact } from '@aztec/protocol-contracts/gas-token'; -import { computeSlotForMapping } from '@aztec/simulator'; - -import { createCompatibleClient } from '../client.js'; - -export async function getBalance( - address: AztecAddress, - maybeTokenAddress: string | undefined, - rpcUrl: string, - debugLogger: DebugLogger, - log: LogFn, -) { - const client = await createCompatibleClient(rpcUrl, debugLogger); - const tokenAddress = maybeTokenAddress ? AztecAddress.fromString(maybeTokenAddress) : GasTokenAddress; - - // Get private balance - if (!tokenAddress.equals(GasTokenAddress)) { - const result = await client.simulateUnconstrained(`balance_of_private`, [address], tokenAddress); - log(`\nPrivate balance: ${result.toString()}`); - } - - // TODO(#6707): For public balance, we cannot directly simulate a public function call, so we read directly from storage as a workaround - const balancesStorageSlot = tokenAddress.equals(GasTokenAddress) - ? GasTokenArtifact.storageLayout.balances.slot - : TokenContractArtifact.storageLayout.public_balances.slot; - const slot = computeSlotForMapping(balancesStorageSlot, address); - const result = await client.getPublicStorageAt(tokenAddress, slot); - log(`Public balance: ${result.toBigInt()}`); -} diff --git a/yarn-project/cli/src/cmds/bootstrap.ts b/yarn-project/cli/src/cmds/infrastructure/bootstrap.ts similarity index 85% rename from yarn-project/cli/src/cmds/bootstrap.ts rename to yarn-project/cli/src/cmds/infrastructure/bootstrap.ts index b23d511af6c..b97bac4ed5f 100644 --- a/yarn-project/cli/src/cmds/bootstrap.ts +++ b/yarn-project/cli/src/cmds/infrastructure/bootstrap.ts @@ -1,7 +1,6 @@ import { SignerlessWallet, type WaitOpts, createPXEClient, makeFetch } from '@aztec/aztec.js'; import { DefaultMultiCallEntrypoint } from '@aztec/aztec.js/entrypoint'; import { type LogFn } from '@aztec/foundation/log'; -import { GasTokenContract, KeyRegistryContract } from '@aztec/noir-contracts.js'; import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; import { getCanonicalKeyRegistry } from '@aztec/protocol-contracts/key-registry'; @@ -11,6 +10,10 @@ const waitOpts: WaitOpts = { }; export async function bootstrap(rpcUrl: string, log: LogFn) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore - Importing noir-contracts.js even in devDeps results in a circular dependency error. Need to ignore because this line doesn't cause an error in a dev environment + const { GasTokenContract, KeyRegistryContract } = await import('@aztec/noir-contracts.js'); + const pxe = createPXEClient(rpcUrl, makeFetch([], true)); const deployer = new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(31337, 1)); diff --git a/yarn-project/cli/src/cmds/infrastructure/index.ts b/yarn-project/cli/src/cmds/infrastructure/index.ts new file mode 100644 index 00000000000..1bb9dfc9a02 --- /dev/null +++ b/yarn-project/cli/src/cmds/infrastructure/index.ts @@ -0,0 +1,51 @@ +import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; + +import { type Command } from 'commander'; + +import { API_KEY, ETHEREUM_HOST, parseOptionalInteger, pxeOption } from '../../utils/commands.js'; + +export function injectCommands(program: Command, log: LogFn, debugLogger: DebugLogger) { + program + .command('bootstrap') + .description('Bootstrap the blockchain') + .addOption(pxeOption) + .action(async options => { + const { bootstrap } = await import('./bootstrap.js'); + await bootstrap(options.rpcUrl, log); + }); + + program + .command('sequencers') + .argument('', 'Command to run: list, add, remove, who-next') + .argument('[who]', 'Who to add/remove') + .description('Manages or queries registered sequencers on the L1 rollup contract.') + .requiredOption( + '--l1-rpc-url ', + 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', + ETHEREUM_HOST, + ) + .option('-a, --api-key ', 'Api key for the ethereum host', API_KEY) + .option( + '-m, --mnemonic ', + 'The mnemonic for the sender of the tx', + 'test test test test test test test test test test test junk', + ) + .option('--block-number ', 'Block number to query next sequencer for', parseOptionalInteger) + .addOption(pxeOption) + .action(async (command, who, options) => { + const { sequencers } = await import('./sequencers.js'); + await sequencers({ + command: command, + who, + mnemonic: options.mnemonic, + rpcUrl: options.rpcUrl, + l1RpcUrl: options.l1RpcUrl, + apiKey: options.apiKey ?? '', + blockNumber: options.blockNumber, + log, + debugLogger, + }); + }); + + return program; +} diff --git a/yarn-project/cli/src/cmds/sequencers.ts b/yarn-project/cli/src/cmds/infrastructure/sequencers.ts similarity index 98% rename from yarn-project/cli/src/cmds/sequencers.ts rename to yarn-project/cli/src/cmds/infrastructure/sequencers.ts index cc53c083547..473d08207e2 100644 --- a/yarn-project/cli/src/cmds/sequencers.ts +++ b/yarn-project/cli/src/cmds/infrastructure/sequencers.ts @@ -5,7 +5,7 @@ import { RollupAbi } from '@aztec/l1-artifacts'; import { createPublicClient, createWalletClient, getContract, http } from 'viem'; import { mnemonicToAccount } from 'viem/accounts'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function sequencers(opts: { command: 'list' | 'add' | 'remove' | 'who-next'; diff --git a/yarn-project/cli/src/cmds/bridge_l1_gas.ts b/yarn-project/cli/src/cmds/l1/bridge_l1_gas.ts similarity index 90% rename from yarn-project/cli/src/cmds/bridge_l1_gas.ts rename to yarn-project/cli/src/cmds/l1/bridge_l1_gas.ts index 08428f979bb..6c944954adf 100644 --- a/yarn-project/cli/src/cmds/bridge_l1_gas.ts +++ b/yarn-project/cli/src/cmds/l1/bridge_l1_gas.ts @@ -2,8 +2,8 @@ import { type AztecAddress } from '@aztec/circuits.js'; import { createEthereumChain, createL1Clients } from '@aztec/ethereum'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; -import { GasPortalManagerFactory } from '../gas_portal.js'; +import { createCompatibleClient } from '../../client.js'; +import { GasPortalManagerFactory } from '../../gas_portal.js'; export async function bridgeL1Gas( amount: bigint, diff --git a/yarn-project/cli/src/cmds/deploy_l1_contracts.ts b/yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts similarity index 93% rename from yarn-project/cli/src/cmds/deploy_l1_contracts.ts rename to yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts index 629dcaec1c7..8541cf380c9 100644 --- a/yarn-project/cli/src/cmds/deploy_l1_contracts.ts +++ b/yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts @@ -1,6 +1,6 @@ import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { deployAztecContracts } from '../utils.js'; +import { deployAztecContracts } from '../../utils/aztec.js'; export async function deployL1Contracts( rpcUrl: string, diff --git a/yarn-project/cli/src/cmds/deploy_l1_verifier.ts b/yarn-project/cli/src/cmds/l1/deploy_l1_verifier.ts similarity index 86% rename from yarn-project/cli/src/cmds/deploy_l1_verifier.ts rename to yarn-project/cli/src/cmds/l1/deploy_l1_verifier.ts index 830f1ea05ba..a10a1957137 100644 --- a/yarn-project/cli/src/cmds/deploy_l1_verifier.ts +++ b/yarn-project/cli/src/cmds/l1/deploy_l1_verifier.ts @@ -1,7 +1,5 @@ -import { BBCircuitVerifier } from '@aztec/bb-prover'; import { createL1Clients, deployL1Contract } from '@aztec/ethereum'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { MockVerifierAbi, MockVerifierBytecode, RollupAbi } from '@aztec/l1-artifacts'; import { InvalidOptionArgumentError } from 'commander'; // @ts-expect-error solc-js doesn't publish its types https://github.com/ethereum/solc-js/issues/689 @@ -9,7 +7,7 @@ import solc from 'solc'; import { getContract } from 'viem'; import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function deployUltraVerifier( ethRpcUrl: string, @@ -24,6 +22,10 @@ export async function deployUltraVerifier( if (!bbBinaryPath || !bbWorkingDirectory) { throw new InvalidOptionArgumentError('Missing path to bb binary and working directory'); } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore - Importing bb-prover even in devDeps results in a circular dependency error through @aztec/simulator. Need to ignore because this line doesn't cause an error in a dev environment + const { BBCircuitVerifier } = await import('@aztec/bb-prover'); + const circuitVerifier = await BBCircuitVerifier.new({ bbBinaryPath, bbWorkingDirectory }); const contractSrc = await circuitVerifier.generateSolidityContract('RootRollupArtifact', 'UltraVerifier.sol'); log('Generated UltraVerifier contract'); @@ -67,6 +69,8 @@ export async function deployUltraVerifier( const pxe = await createCompatibleClient(pxeRpcUrl, debugLogger); const { l1ContractAddresses } = await pxe.getNodeInfo(); + const { RollupAbi } = await import('@aztec/l1-artifacts'); + const rollup = getContract({ abi: RollupAbi, address: l1ContractAddresses.rollupAddress.toString(), @@ -89,6 +93,7 @@ export async function deployMockVerifier( ? mnemonicToAccount(mnemonic!) : privateKeyToAccount(`${privateKey.startsWith('0x') ? '' : '0x'}${privateKey}` as `0x${string}`); const { publicClient, walletClient } = createL1Clients(ethRpcUrl, account); + const { MockVerifierAbi, MockVerifierBytecode, RollupAbi } = await import('@aztec/l1-artifacts'); const mockVerifierAddress = await deployL1Contract(walletClient, publicClient, MockVerifierAbi, MockVerifierBytecode); log(`Deployed MockVerifier at ${mockVerifierAddress.toString()}`); diff --git a/yarn-project/cli/src/cmds/get_l1_balance.ts b/yarn-project/cli/src/cmds/l1/get_l1_balance.ts similarity index 94% rename from yarn-project/cli/src/cmds/get_l1_balance.ts rename to yarn-project/cli/src/cmds/l1/get_l1_balance.ts index 26163191c42..85e216acc4e 100644 --- a/yarn-project/cli/src/cmds/get_l1_balance.ts +++ b/yarn-project/cli/src/cmds/l1/get_l1_balance.ts @@ -5,7 +5,7 @@ import { PortalERC20Abi } from '@aztec/l1-artifacts'; import { createPublicClient, getContract, http } from 'viem'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function getL1Balance( who: EthAddress, diff --git a/yarn-project/cli/src/cmds/l1/index.ts b/yarn-project/cli/src/cmds/l1/index.ts new file mode 100644 index 00000000000..67fb0bc06a1 --- /dev/null +++ b/yarn-project/cli/src/cmds/l1/index.ts @@ -0,0 +1,134 @@ +import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; + +import { type Command } from 'commander'; + +import { + API_KEY, + ETHEREUM_HOST, + PRIVATE_KEY, + parseAztecAddress, + parseBigint, + parseEthereumAddress, + pxeOption, +} from '../../utils/commands.js'; + +export function injectCommands(program: Command, log: LogFn, debugLogger: DebugLogger) { + program + .command('deploy-l1-contracts') + .description('Deploys all necessary Ethereum contracts for Aztec.') + .requiredOption( + '-u, --rpc-url ', + 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', + ETHEREUM_HOST, + ) + .option('-a, --api-key ', 'Api key for the ethereum host', API_KEY) + .requiredOption('-p, --private-key ', 'The private key to use for deployment', PRIVATE_KEY) + .option( + '-m, --mnemonic ', + 'The mnemonic to use in deployment', + 'test test test test test test test test test test test junk', + ) + .action(async options => { + const { deployL1Contracts } = await import('./deploy_l1_contracts.js'); + await deployL1Contracts( + options.rpcUrl, + options.apiKey ?? '', + options.privateKey, + options.mnemonic, + log, + debugLogger, + ); + }); + + program + .command('deploy-l1-verifier') + .description('Deploys the rollup verifier contract') + .requiredOption( + '--eth-rpc-url ', + 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', + ETHEREUM_HOST, + ) + .addOption(pxeOption) + .requiredOption('-p, --private-key ', 'The private key to use for deployment', PRIVATE_KEY) + .option( + '-m, --mnemonic ', + 'The mnemonic to use in deployment', + 'test test test test test test test test test test test junk', + ) + .requiredOption('--verifier ', 'Either mock or real', 'real') + .option('--bb ', 'Path to bb binary') + .option('--bb-working-dir ', 'Path to bb working directory') + .action(async options => { + const { deployMockVerifier, deployUltraVerifier } = await import('./deploy_l1_verifier.js'); + if (options.verifier === 'mock') { + await deployMockVerifier( + options.ethRpcUrl, + options.privateKey, + options.mnemonic, + options.rpcUrl, + log, + debugLogger, + ); + } else { + await deployUltraVerifier( + options.ethRpcUrl, + options.privateKey, + options.mnemonic, + options.rpcUrl, + options.bb, + options.bbWorkingDir, + log, + debugLogger, + ); + } + }); + + program + .command('bridge-l1-gas') + .description('Mints L1 gas tokens and pushes them to L2.') + .argument('', 'The amount of gas tokens to mint and bridge.', parseBigint) + .argument('', 'Aztec address of the recipient.', parseAztecAddress) + .requiredOption( + '--l1-rpc-url ', + 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', + ETHEREUM_HOST, + ) + .option('-a, --api-key ', 'Api key for the ethereum host', API_KEY) + .option( + '-m, --mnemonic ', + 'The mnemonic to use for deriving the Ethereum address that will mint and bridge', + 'test test test test test test test test test test test junk', + ) + .addOption(pxeOption) + .action(async (amount, recipient, options) => { + const { bridgeL1Gas } = await import('./bridge_l1_gas.js'); + await bridgeL1Gas( + amount, + recipient, + options.rpcUrl, + options.l1RpcUrl, + options.apiKey ?? '', + options.mnemonic, + log, + debugLogger, + ); + }); + + program + .command('get-l1-balance') + .description('Gets the balance of gas tokens in L1 for the given Ethereum address.') + .argument('', 'Ethereum address to check.', parseEthereumAddress) + .requiredOption( + '--l1-rpc-url ', + 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', + ETHEREUM_HOST, + ) + .option('-a, --api-key ', 'Api key for the ethereum host', API_KEY) + .addOption(pxeOption) + .action(async (who, options) => { + const { getL1Balance } = await import('./get_l1_balance.js'); + await getL1Balance(who, options.rpcUrl, options.l1RpcUrl, options.apiKey ?? '', log, debugLogger); + }); + + return program; +} diff --git a/yarn-project/cli/src/cmds/add_contract.ts b/yarn-project/cli/src/cmds/pxe/add_contract.ts similarity index 92% rename from yarn-project/cli/src/cmds/add_contract.ts rename to yarn-project/cli/src/cmds/pxe/add_contract.ts index 5f13f5044a3..8c7f57a391c 100644 --- a/yarn-project/cli/src/cmds/add_contract.ts +++ b/yarn-project/cli/src/cmds/pxe/add_contract.ts @@ -3,8 +3,8 @@ import { type PublicKeys } from '@aztec/circuits.js'; import { computeContractAddressFromInstance } from '@aztec/circuits.js/contract'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; -import { getContractArtifact } from '../utils.js'; +import { createCompatibleClient } from '../../client.js'; +import { getContractArtifact } from '../../utils/aztec.js'; export async function addContract( rpcUrl: string, diff --git a/yarn-project/cli/src/cmds/add_note.ts b/yarn-project/cli/src/cmds/pxe/add_note.ts similarity index 86% rename from yarn-project/cli/src/cmds/add_note.ts rename to yarn-project/cli/src/cmds/pxe/add_note.ts index 68debccd90c..990027573dc 100644 --- a/yarn-project/cli/src/cmds/add_note.ts +++ b/yarn-project/cli/src/cmds/pxe/add_note.ts @@ -2,8 +2,8 @@ import { type AztecAddress, type Fr, type NoteSelector } from '@aztec/aztec.js'; import { ExtendedNote, Note, type TxHash } from '@aztec/circuit-types'; import { type DebugLogger } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; -import { parseFields } from '../parse_args.js'; +import { createCompatibleClient } from '../../client.js'; +import { parseFields } from '../../utils/commands.js'; export async function addNote( address: AztecAddress, diff --git a/yarn-project/cli/src/cmds/block_number.ts b/yarn-project/cli/src/cmds/pxe/block_number.ts similarity index 83% rename from yarn-project/cli/src/cmds/block_number.ts rename to yarn-project/cli/src/cmds/pxe/block_number.ts index 5b6ca472d6b..a4c017a2a75 100644 --- a/yarn-project/cli/src/cmds/block_number.ts +++ b/yarn-project/cli/src/cmds/pxe/block_number.ts @@ -1,6 +1,6 @@ import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function blockNumber(rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); diff --git a/yarn-project/cli/src/cmds/call.ts b/yarn-project/cli/src/cmds/pxe/call.ts similarity index 88% rename from yarn-project/cli/src/cmds/call.ts rename to yarn-project/cli/src/cmds/pxe/call.ts index db165bb9f3d..dcc9eb750dd 100644 --- a/yarn-project/cli/src/cmds/call.ts +++ b/yarn-project/cli/src/cmds/pxe/call.ts @@ -4,8 +4,9 @@ import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; import { format } from 'util'; -import { createCompatibleClient } from '../client.js'; -import { getFunctionArtifact, getTxSender, prepTx } from '../utils.js'; +import { createCompatibleClient } from '../../client.js'; +import { getFunctionArtifact, prepTx } from '../../utils/aztec.js'; +import { getTxSender } from '../../utils/commands.js'; export async function call( functionName: string, diff --git a/yarn-project/cli/src/cmds/create_account.ts b/yarn-project/cli/src/cmds/pxe/create_account.ts similarity index 92% rename from yarn-project/cli/src/cmds/create_account.ts rename to yarn-project/cli/src/cmds/pxe/create_account.ts index fb43496eff6..920dfb27dcd 100644 --- a/yarn-project/cli/src/cmds/create_account.ts +++ b/yarn-project/cli/src/cmds/pxe/create_account.ts @@ -1,11 +1,10 @@ -import { getSchnorrAccount } from '@aztec/accounts/schnorr'; import { type DeployAccountOptions } from '@aztec/aztec.js'; import { deriveSigningKey } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; -import { type IFeeOpts, printGasEstimates } from '../fees.js'; +import { createCompatibleClient } from '../../client.js'; +import { type IFeeOpts, printGasEstimates } from '../../fees.js'; export async function createAccount( rpcUrl: string, @@ -22,6 +21,7 @@ export async function createAccount( const printPK = typeof privateKey === 'undefined'; privateKey ??= Fr.random(); const salt = Fr.ZERO; + const { getSchnorrAccount } = await import('@aztec/accounts/schnorr'); const account = getSchnorrAccount(client, privateKey, deriveSigningKey(privateKey), salt); const { address, publicKeys, partialAddress } = account.getCompleteAddress(); diff --git a/yarn-project/cli/src/cmds/deploy.ts b/yarn-project/cli/src/cmds/pxe/deploy.ts similarity index 92% rename from yarn-project/cli/src/cmds/deploy.ts rename to yarn-project/cli/src/cmds/pxe/deploy.ts index c80c45dda4e..e6a2357c090 100644 --- a/yarn-project/cli/src/cmds/deploy.ts +++ b/yarn-project/cli/src/cmds/pxe/deploy.ts @@ -1,14 +1,13 @@ -import { getSchnorrAccount } from '@aztec/accounts/schnorr'; import { ContractDeployer, type DeployMethod, Fr } from '@aztec/aztec.js'; import { type PublicKeys, deriveSigningKey } from '@aztec/circuits.js'; import { getInitializer } from '@aztec/foundation/abi'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; -import { encodeArgs } from '../encoding.js'; -import { type IFeeOpts, printGasEstimates } from '../fees.js'; -import { GITHUB_TAG_PREFIX } from '../github.js'; -import { getContractArtifact } from '../utils.js'; +import { createCompatibleClient } from '../../client.js'; +import { encodeArgs } from '../../encoding.js'; +import { type IFeeOpts, printGasEstimates } from '../../fees.js'; +import { GITHUB_TAG_PREFIX } from '../../github.js'; +import { getContractArtifact } from '../../utils/aztec.js'; export async function deploy( artifactPath: string, @@ -41,6 +40,7 @@ export async function deploy( `\nWarning: Contract was compiled with a different version of Aztec.nr: ${contractArtifact.aztecNrVersion}. Consider updating Aztec.nr to ${expectedAztecNrVersion}\n`, ); } + const { getSchnorrAccount } = await import('@aztec/accounts/schnorr'); const wallet = await getSchnorrAccount(client, privateKey, deriveSigningKey(privateKey), Fr.ZERO).getWallet(); const deployer = new ContractDeployer(contractArtifact, wallet, publicKeys?.hash() ?? Fr.ZERO, initializer); diff --git a/yarn-project/cli/src/cmds/get_account.ts b/yarn-project/cli/src/cmds/pxe/get_account.ts similarity index 89% rename from yarn-project/cli/src/cmds/get_account.ts rename to yarn-project/cli/src/cmds/pxe/get_account.ts index c672c85fb85..9d4e01bf590 100644 --- a/yarn-project/cli/src/cmds/get_account.ts +++ b/yarn-project/cli/src/cmds/pxe/get_account.ts @@ -1,7 +1,7 @@ import { type AztecAddress } from '@aztec/aztec.js'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function getAccount(aztecAddress: AztecAddress, rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); diff --git a/yarn-project/cli/src/cmds/get_accounts.ts b/yarn-project/cli/src/cmds/pxe/get_accounts.ts similarity index 93% rename from yarn-project/cli/src/cmds/get_accounts.ts rename to yarn-project/cli/src/cmds/pxe/get_accounts.ts index 204842f4387..81e6bffd462 100644 --- a/yarn-project/cli/src/cmds/get_accounts.ts +++ b/yarn-project/cli/src/cmds/pxe/get_accounts.ts @@ -1,6 +1,6 @@ import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function getAccounts( rpcUrl: string, diff --git a/yarn-project/cli/src/cmds/get_block.ts b/yarn-project/cli/src/cmds/pxe/get_block.ts similarity index 90% rename from yarn-project/cli/src/cmds/get_block.ts rename to yarn-project/cli/src/cmds/pxe/get_block.ts index c27ee92c303..37e22c6461d 100644 --- a/yarn-project/cli/src/cmds/get_block.ts +++ b/yarn-project/cli/src/cmds/pxe/get_block.ts @@ -1,7 +1,7 @@ import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; -import { inspectBlock } from '../inspect.js'; +import { createCompatibleClient } from '../../client.js'; +import { inspectBlock } from '../../inspect.js'; export async function getBlock( rpcUrl: string, diff --git a/yarn-project/cli/src/cmds/get_contract_data.ts b/yarn-project/cli/src/cmds/pxe/get_contract_data.ts similarity index 96% rename from yarn-project/cli/src/cmds/get_contract_data.ts rename to yarn-project/cli/src/cmds/pxe/get_contract_data.ts index 389af5af00a..a625bc25f32 100644 --- a/yarn-project/cli/src/cmds/get_contract_data.ts +++ b/yarn-project/cli/src/cmds/pxe/get_contract_data.ts @@ -1,7 +1,7 @@ import { type AztecAddress } from '@aztec/aztec.js'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function getContractData( rpcUrl: string, diff --git a/yarn-project/cli/src/cmds/get_logs.ts b/yarn-project/cli/src/cmds/pxe/get_logs.ts similarity index 96% rename from yarn-project/cli/src/cmds/get_logs.ts rename to yarn-project/cli/src/cmds/pxe/get_logs.ts index 871dc3c8291..c38dd956acb 100644 --- a/yarn-project/cli/src/cmds/get_logs.ts +++ b/yarn-project/cli/src/cmds/pxe/get_logs.ts @@ -2,7 +2,7 @@ import { type AztecAddress, type LogFilter, type LogId, type TxHash } from '@azt import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; import { sleep } from '@aztec/foundation/sleep'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function getLogs( txHash: TxHash, diff --git a/yarn-project/cli/src/cmds/get_node_info.ts b/yarn-project/cli/src/cmds/pxe/get_node_info.ts similarity index 94% rename from yarn-project/cli/src/cmds/get_node_info.ts rename to yarn-project/cli/src/cmds/pxe/get_node_info.ts index 488fb810443..3cf45c689d6 100644 --- a/yarn-project/cli/src/cmds/get_node_info.ts +++ b/yarn-project/cli/src/cmds/pxe/get_node_info.ts @@ -1,6 +1,6 @@ import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function getNodeInfo(rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); diff --git a/yarn-project/cli/src/cmds/get_pxe_info.ts b/yarn-project/cli/src/cmds/pxe/get_pxe_info.ts similarity index 93% rename from yarn-project/cli/src/cmds/get_pxe_info.ts rename to yarn-project/cli/src/cmds/pxe/get_pxe_info.ts index 20047ac7ce3..b8f20b61af4 100644 --- a/yarn-project/cli/src/cmds/get_pxe_info.ts +++ b/yarn-project/cli/src/cmds/pxe/get_pxe_info.ts @@ -1,6 +1,6 @@ import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function getPXEInfo(rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); diff --git a/yarn-project/cli/src/cmds/get_recipient.ts b/yarn-project/cli/src/cmds/pxe/get_recipient.ts similarity index 89% rename from yarn-project/cli/src/cmds/get_recipient.ts rename to yarn-project/cli/src/cmds/pxe/get_recipient.ts index 4ae6baac896..7946bea6d99 100644 --- a/yarn-project/cli/src/cmds/get_recipient.ts +++ b/yarn-project/cli/src/cmds/pxe/get_recipient.ts @@ -1,7 +1,7 @@ import { type AztecAddress } from '@aztec/aztec.js'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function getRecipient(aztecAddress: AztecAddress, rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); diff --git a/yarn-project/cli/src/cmds/get_recipients.ts b/yarn-project/cli/src/cmds/pxe/get_recipients.ts similarity index 89% rename from yarn-project/cli/src/cmds/get_recipients.ts rename to yarn-project/cli/src/cmds/pxe/get_recipients.ts index bc091bc5dd6..5f6a02cb306 100644 --- a/yarn-project/cli/src/cmds/get_recipients.ts +++ b/yarn-project/cli/src/cmds/pxe/get_recipients.ts @@ -1,6 +1,6 @@ import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function getRecipients(rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); diff --git a/yarn-project/cli/src/cmds/get_tx.ts b/yarn-project/cli/src/cmds/pxe/get_tx.ts similarity index 77% rename from yarn-project/cli/src/cmds/get_tx.ts rename to yarn-project/cli/src/cmds/pxe/get_tx.ts index 9c38b6c9cfc..b91a0d82126 100644 --- a/yarn-project/cli/src/cmds/get_tx.ts +++ b/yarn-project/cli/src/cmds/pxe/get_tx.ts @@ -1,8 +1,8 @@ import { type TxHash } from '@aztec/aztec.js'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; -import { inspectTx } from '../inspect.js'; +import { createCompatibleClient } from '../../client.js'; +import { inspectTx } from '../../inspect.js'; export async function getTx(rpcUrl: string, txHash: TxHash, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); diff --git a/yarn-project/cli/src/cmds/pxe/index.ts b/yarn-project/cli/src/cmds/pxe/index.ts new file mode 100644 index 00000000000..fb86c3ae2a1 --- /dev/null +++ b/yarn-project/cli/src/cmds/pxe/index.ts @@ -0,0 +1,377 @@ +import { Fr, PublicKeys } from '@aztec/circuits.js'; +import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; + +import { type Command } from 'commander'; + +import { FeeOpts } from '../../fees.js'; +import { + addOptions, + createPrivateKeyOption, + logJson, + parseAztecAddress, + parseEthereumAddress, + parseField, + parseFieldFromHexString, + parseOptionalAztecAddress, + parseOptionalInteger, + parseOptionalLogId, + parseOptionalTxHash, + parsePartialAddress, + parsePublicKey, + parseTxHash, + pxeOption, +} from '../../utils/commands.js'; + +export function injectCommands(program: Command, log: LogFn, debugLogger: DebugLogger) { + const createAccountCommand = program + .command('create-account') + .description( + 'Creates an aztec account that can be used for sending transactions. Registers the account on the PXE and deploys an account contract. Uses a Schnorr single-key account which uses the same key for encryption and authentication (not secure for production usage).', + ) + .summary('Creates an aztec account that can be used for sending transactions.') + .option( + '--skip-initialization', + 'Skip initializing the account contract. Useful for publicly deploying an existing account.', + ) + .option('--public-deploy', 'Publicly deploys the account and registers the class if needed.') + .addOption(createPrivateKeyOption('Private key for account. Uses random by default.', false)) + .addOption(pxeOption); + + addOptions(createAccountCommand, FeeOpts.getOptions()) + .option( + '--register-only', + 'Just register the account on the PXE. Do not deploy or initialize the account contract.', + ) + // `options.wait` is default true. Passing `--no-wait` will set it to false. + // https://github.com/tj/commander.js#other-option-types-negatable-boolean-and-booleanvalue + .option('--no-wait', 'Skip waiting for the contract to be deployed. Print the hash of deployment transaction') + .action(async args => { + const { createAccount } = await import('./create_account.js'); + const { rpcUrl, privateKey, wait, registerOnly, skipInitialization, publicDeploy } = args; + await createAccount( + rpcUrl, + privateKey, + registerOnly, + skipInitialization, + publicDeploy, + wait, + FeeOpts.fromCli(args, log), + debugLogger, + log, + ); + }); + + const deployCommand = program + .command('deploy') + .description('Deploys a compiled Aztec.nr contract to Aztec.') + .argument( + '', + "A compiled Aztec.nr contract's artifact in JSON format or name of a contract artifact exported by @aztec/noir-contracts.js", + ) + .option('--initialize ', 'The contract initializer function to call', 'constructor') + .option('--no-initialize') + .option('-a, --args ', 'Contract constructor arguments', []) + .addOption(pxeOption) + .option( + '-k, --public-key ', + 'Optional encryption public key for this address. Set this value only if this contract is expected to receive private notes, which will be encrypted using this public key.', + parsePublicKey, + ) + .option( + '-s, --salt ', + 'Optional deployment salt as a hex string for generating the deployment address.', + parseFieldFromHexString, + ) + .option('--universal', 'Do not mix the sender address into the deployment.') + .addOption(createPrivateKeyOption("The sender's private key.", true)) + .option('--json', 'Emit output as json') + // `options.wait` is default true. Passing `--no-wait` will set it to false. + // https://github.com/tj/commander.js#other-option-types-negatable-boolean-and-booleanvalue + .option('--no-wait', 'Skip waiting for the contract to be deployed. Print the hash of deployment transaction') + .option('--class-registration', 'Register the contract class. Only has to be done once') + .option('--no-class-registration', 'Skip registering the contract class') + .option('--public-deployment', 'Deploy the public bytecode of contract') + .option('--no-public-deployment', "Skip deploying the contract's public bytecode"); + addOptions(deployCommand, FeeOpts.getOptions()).action(async (artifactPath, opts) => { + const { deploy } = await import('./deploy.js'); + const { + json, + rpcUrl, + publicKey, + args: rawArgs, + salt, + wait, + privateKey, + classRegistration, + initialize, + publicDeployment, + universal, + } = opts; + await deploy( + artifactPath, + json, + rpcUrl, + publicKey ? PublicKeys.fromString(publicKey) : undefined, + rawArgs, + salt, + privateKey, + typeof initialize === 'string' ? initialize : undefined, + !publicDeployment, + !classRegistration, + typeof initialize === 'string' ? false : initialize, + universal, + wait, + FeeOpts.fromCli(opts, log), + debugLogger, + log, + logJson(log), + ); + }); + + program + .command('add-contract') + .description( + 'Adds an existing contract to the PXE. This is useful if you have deployed a contract outside of the PXE and want to use it with the PXE.', + ) + .requiredOption( + '-c, --contract-artifact ', + "A compiled Aztec.nr contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts.js", + ) + .requiredOption('-ca, --contract-address
', 'Aztec address of the contract.', parseAztecAddress) + .requiredOption('--init-hash ', 'Initialization hash', parseFieldFromHexString) + .option('--salt ', 'Optional deployment salt', parseFieldFromHexString) + .option('-p, --public-key ', 'Optional public key for this contract', parsePublicKey) + .option('--portal-address
', 'Optional address to a portal contract on L1', parseEthereumAddress) + .option('--deployer-address
', 'Optional address of the contract deployer', parseAztecAddress) + .addOption(pxeOption) + .action(async options => { + const { addContract } = await import('./add_contract.js'); + await addContract( + options.rpcUrl, + options.contractArtifact, + options.contractAddress, + options.initHash, + options.salt ?? Fr.ZERO, + options.publicKey, + options.deployerAddress, + debugLogger, + log, + ); + }); + + program + .command('get-tx') + .description('Gets the receipt for the specified transaction hash.') + .argument('', 'A transaction hash to get the receipt for.', parseTxHash) + .addOption(pxeOption) + .action(async (txHash, options) => { + const { getTx } = await import('./get_tx.js'); + await getTx(options.rpcUrl, txHash, debugLogger, log); + }); + + program + .command('get-block') + .description('Gets info for a given block or latest.') + .argument('[blockNumber]', 'Block height', parseOptionalInteger) + .option('-f, --follow', 'Keep polling for new blocks') + .addOption(pxeOption) + .action(async (blockNumber, options) => { + const { getBlock } = await import('./get_block.js'); + await getBlock(options.rpcUrl, blockNumber, options.follow, debugLogger, log); + }); + + program + .command('get-contract-data') + .description('Gets information about the Aztec contract deployed at the specified address.') + .argument('', 'Aztec address of the contract.', parseAztecAddress) + .addOption(pxeOption) + .option('-b, --include-bytecode ', "Include the contract's public function bytecode, if any.", false) + .action(async (contractAddress, options) => { + const { getContractData } = await import('./get_contract_data.js'); + await getContractData(options.rpcUrl, contractAddress, options.includeBytecode, debugLogger, log); + }); + + program + .command('get-logs') + .description('Gets all the unencrypted logs from an intersection of all the filter params.') + .option('-tx, --tx-hash ', 'A transaction hash to get the receipt for.', parseOptionalTxHash) + .option( + '-fb, --from-block ', + 'Initial block number for getting logs (defaults to 1).', + parseOptionalInteger, + ) + .option('-tb, --to-block ', 'Up to which block to fetch logs (defaults to latest).', parseOptionalInteger) + .option('-al --after-log ', 'ID of a log after which to fetch the logs.', parseOptionalLogId) + .option('-ca, --contract-address
', 'Contract address to filter logs by.', parseOptionalAztecAddress) + .addOption(pxeOption) + .option('--follow', 'If set, will keep polling for new logs until interrupted.') + .action(async ({ txHash, fromBlock, toBlock, afterLog, contractAddress, rpcUrl, follow }) => { + const { getLogs } = await import('./get_logs.js'); + await getLogs(txHash, fromBlock, toBlock, afterLog, contractAddress, rpcUrl, follow, debugLogger, log); + }); + + program + .command('register-recipient') + .description('Register a recipient in the PXE.') + .requiredOption('-a, --address ', "The account's Aztec address.", parseAztecAddress) + .requiredOption('-p, --public-key ', 'The account public key.', parsePublicKey) + .requiredOption( + '-pa, --partial-address ', + 'The partially computed address of the account contract.', + parsePartialAddress, + ) + .addOption(pxeOption) + .action(async ({ address, publicKey, partialAddress, rpcUrl }) => { + const { registerRecipient } = await import('./register_recipient.js'); + await registerRecipient(address, publicKey, partialAddress, rpcUrl, debugLogger, log); + }); + + program + .command('get-accounts') + .description('Gets all the Aztec accounts stored in the PXE.') + .addOption(pxeOption) + .option('--json', 'Emit output as json') + .action(async (options: any) => { + const { getAccounts } = await import('./get_accounts.js'); + await getAccounts(options.rpcUrl, options.json, debugLogger, log, logJson(log)); + }); + + program + .command('get-account') + .description('Gets an account given its Aztec address.') + .argument('
', 'The Aztec address to get account for', parseAztecAddress) + .addOption(pxeOption) + .action(async (address, options) => { + const { getAccount } = await import('./get_account.js'); + await getAccount(address, options.rpcUrl, debugLogger, log); + }); + + program + .command('get-recipients') + .description('Gets all the recipients stored in the PXE.') + .addOption(pxeOption) + .action(async (options: any) => { + const { getRecipients } = await import('./get_recipients.js'); + await getRecipients(options.rpcUrl, debugLogger, log); + }); + + program + .command('get-recipient') + .description('Gets a recipient given its Aztec address.') + .argument('
', 'The Aztec address to get recipient for', parseAztecAddress) + .addOption(pxeOption) + .action(async (address, options) => { + const { getRecipient } = await import('./get_recipient.js'); + await getRecipient(address, options.rpcUrl, debugLogger, log); + }); + + const sendCommand = program + .command('send') + .description('Calls a function on an Aztec contract.') + .argument('', 'Name of function to execute') + .option('-a, --args [functionArgs...]', 'Function arguments', []) + .requiredOption( + '-c, --contract-artifact ', + "A compiled Aztec.nr contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts.js", + ) + .requiredOption('-ca, --contract-address
', 'Aztec address of the contract.', parseAztecAddress) + .addOption(createPrivateKeyOption("The sender's private key.", true)) + .addOption(pxeOption) + .option('--no-wait', 'Print transaction hash without waiting for it to be mined'); + addOptions(sendCommand, FeeOpts.getOptions()).action(async (functionName, options) => { + const { send } = await import('./send.js'); + await send( + functionName, + options.args, + options.contractArtifact, + options.contractAddress, + options.privateKey, + options.rpcUrl, + !options.noWait, + FeeOpts.fromCli(options, log), + debugLogger, + log, + ); + }); + + program + .command('call') + .description( + 'Simulates the execution of a view (read-only) function on a deployed contract, without modifying state.', + ) + .argument('', 'Name of function to call') + .option('-a, --args [functionArgs...]', 'Function arguments', []) + .requiredOption( + '-c, --contract-artifact ', + "A compiled Aztec.nr contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts.js", + ) + .requiredOption('-ca, --contract-address
', 'Aztec address of the contract.', parseAztecAddress) + .option('-f, --from ', 'Aztec address of the caller. If empty, will use the first account from RPC.') + .addOption(pxeOption) + .action(async (functionName, options) => { + const { call } = await import('./call.js'); + await call( + functionName, + options.args, + options.contractArtifact, + options.contractAddress, + options.from, + options.rpcUrl, + debugLogger, + log, + ); + }); + + program + .command('add-note') + .description('Adds a note to the database in the PXE.') + .argument('
', 'The Aztec address of the note owner.', parseAztecAddress) + .argument('', 'Aztec address of the contract.', parseAztecAddress) + .argument('', 'The storage slot of the note.', parseField) + .argument('', 'The type ID of the note.', parseField) + .argument('', 'The tx hash of the tx containing the note.', parseTxHash) + .requiredOption('-n, --note [note...]', 'The members of a Note serialized as hex strings.', []) + .addOption(pxeOption) + .action(async (address, contractAddress, storageSlot, noteTypeId, txHash, options) => { + const { addNote } = await import('./add_note.js'); + await addNote( + address, + contractAddress, + storageSlot, + noteTypeId, + txHash, + options.note, + options.rpcUrl, + debugLogger, + ); + }); + + program + .command('block-number') + .description('Gets the current Aztec L2 block number.') + .addOption(pxeOption) + .action(async (options: any) => { + const { blockNumber } = await import('./block_number.js'); + await blockNumber(options.rpcUrl, debugLogger, log); + }); + + program + .command('get-node-info') + .description('Gets the information of an aztec node at a URL.') + .addOption(pxeOption) + .action(async options => { + const { getNodeInfo } = await import('./get_node_info.js'); + await getNodeInfo(options.rpcUrl, debugLogger, log); + }); + + program + .command('get-pxe-info') + .description('Gets the information of a PXE at a URL.') + .addOption(pxeOption) + .action(async options => { + const { getPXEInfo } = await import('./get_pxe_info.js'); + await getPXEInfo(options.rpcUrl, debugLogger, log); + }); + + return program; +} diff --git a/yarn-project/cli/src/cmds/register_recipient.ts b/yarn-project/cli/src/cmds/pxe/register_recipient.ts similarity index 92% rename from yarn-project/cli/src/cmds/register_recipient.ts rename to yarn-project/cli/src/cmds/pxe/register_recipient.ts index 57b2e186317..ba832ff5b63 100644 --- a/yarn-project/cli/src/cmds/register_recipient.ts +++ b/yarn-project/cli/src/cmds/pxe/register_recipient.ts @@ -3,7 +3,7 @@ import { CompleteAddress } from '@aztec/circuit-types'; import { type PublicKeys } from '@aztec/circuits.js'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; +import { createCompatibleClient } from '../../client.js'; export async function registerRecipient( aztecAddress: AztecAddress, diff --git a/yarn-project/cli/src/cmds/send.ts b/yarn-project/cli/src/cmds/pxe/send.ts similarity index 87% rename from yarn-project/cli/src/cmds/send.ts rename to yarn-project/cli/src/cmds/pxe/send.ts index 87e41d64698..8fb7b682ff1 100644 --- a/yarn-project/cli/src/cmds/send.ts +++ b/yarn-project/cli/src/cmds/pxe/send.ts @@ -1,11 +1,10 @@ -import { getSchnorrAccount } from '@aztec/accounts/schnorr'; import { type AztecAddress, Contract, Fr } from '@aztec/aztec.js'; import { deriveSigningKey } from '@aztec/circuits.js'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { createCompatibleClient } from '../client.js'; -import { type IFeeOpts, printGasEstimates } from '../fees.js'; -import { prepTx } from '../utils.js'; +import { createCompatibleClient } from '../../client.js'; +import { type IFeeOpts, printGasEstimates } from '../../fees.js'; +import { prepTx } from '../../utils/aztec.js'; export async function send( functionName: string, @@ -22,6 +21,8 @@ export async function send( const { functionArgs, contractArtifact } = await prepTx(contractArtifactPath, functionName, functionArgsIn, log); const client = await createCompatibleClient(rpcUrl, debugLogger); + const { getSchnorrAccount } = await import('@aztec/accounts/schnorr'); + const wallet = await getSchnorrAccount( client, encryptionPrivateKey, diff --git a/yarn-project/cli/src/cmds/compute_selector.ts b/yarn-project/cli/src/cmds/utils/compute_selector.ts similarity index 100% rename from yarn-project/cli/src/cmds/compute_selector.ts rename to yarn-project/cli/src/cmds/utils/compute_selector.ts diff --git a/yarn-project/cli/src/cmds/example_contracts.ts b/yarn-project/cli/src/cmds/utils/example_contracts.ts similarity index 81% rename from yarn-project/cli/src/cmds/example_contracts.ts rename to yarn-project/cli/src/cmds/utils/example_contracts.ts index 94c7437262b..c2f9d172b45 100644 --- a/yarn-project/cli/src/cmds/example_contracts.ts +++ b/yarn-project/cli/src/cmds/utils/example_contracts.ts @@ -1,6 +1,6 @@ import { type LogFn } from '@aztec/foundation/log'; -import { getExampleContractArtifacts } from '../utils.js'; +import { getExampleContractArtifacts } from '../../utils/aztec.js'; export async function exampleContracts(log: LogFn) { const abisList = await getExampleContractArtifacts(); diff --git a/yarn-project/cli/src/cmds/generate_p2p_private_key.ts b/yarn-project/cli/src/cmds/utils/generate_p2p_private_key.ts similarity index 100% rename from yarn-project/cli/src/cmds/generate_p2p_private_key.ts rename to yarn-project/cli/src/cmds/utils/generate_p2p_private_key.ts diff --git a/yarn-project/cli/src/cmds/generate_private_key.ts b/yarn-project/cli/src/cmds/utils/generate_private_key.ts similarity index 100% rename from yarn-project/cli/src/cmds/generate_private_key.ts rename to yarn-project/cli/src/cmds/utils/generate_private_key.ts diff --git a/yarn-project/cli/src/cmds/utils/index.ts b/yarn-project/cli/src/cmds/utils/index.ts new file mode 100644 index 00000000000..55b90bfd927 --- /dev/null +++ b/yarn-project/cli/src/cmds/utils/index.ts @@ -0,0 +1,47 @@ +import { type LogFn } from '@aztec/foundation/log'; + +import { type Command } from 'commander'; + +export function injectCommands(program: Command, log: LogFn) { + program + .command('generate-keys') + .summary('Generates encryption and signing private keys.') + .description('Generates and encryption and signing private key pair.') + .option( + '-m, --mnemonic', + 'An optional mnemonic string used for the private key generation. If not provided, random private key will be generated.', + ) + .action(async _options => { + const { generateKeys } = await import('./generate_private_key.js'); + const { privateEncryptionKey, privateSigningKey } = generateKeys(); + log(`Encryption Private Key: ${privateEncryptionKey}\nSigning Private key: ${privateSigningKey}\n`); + }); + + program + .command('generate-p2p-private-key') + .summary('Generates a LibP2P peer private key.') + .description('Generates a private key that can be used for running a node on a LibP2P network.') + .action(async () => { + const { generateP2PPrivateKey } = await import('./generate_p2p_private_key.js'); + await generateP2PPrivateKey(log); + }); + + program + .command('example-contracts') + .description('Lists the example contracts available to deploy from @aztec/noir-contracts.js') + .action(async () => { + const { exampleContracts } = await import('./example_contracts.js'); + await exampleContracts(log); + }); + + program + .command('compute-selector') + .description('Given a function signature, it computes a selector') + .argument('', 'Function signature to compute selector for e.g. foo(Field)') + .action(async (functionSignature: string) => { + const { computeSelector } = await import('./compute_selector.js'); + computeSelector(functionSignature, log); + }); + + return program; +} diff --git a/yarn-project/cli/src/fees.ts b/yarn-project/cli/src/fees.ts index 4b0a347197b..34f0d88bdb2 100644 --- a/yarn-project/cli/src/fees.ts +++ b/yarn-project/cli/src/fees.ts @@ -13,7 +13,7 @@ import { type LogFn } from '@aztec/foundation/log'; import { Option } from 'commander'; -import { parseBigint } from './parse_args.js'; +import { parseBigint } from './utils/commands.js'; export type CliFeeArgs = { estimateGasOnly: boolean; diff --git a/yarn-project/cli/src/index.ts b/yarn-project/cli/src/index.ts deleted file mode 100644 index 786a0b09c74..00000000000 --- a/yarn-project/cli/src/index.ts +++ /dev/null @@ -1,688 +0,0 @@ -import { Fr, PublicKeys } from '@aztec/circuits.js'; -import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; -import { fileURLToPath } from '@aztec/foundation/url'; - -import { Command as CommanderCommand, Option } from 'commander'; -import { lookup } from 'dns/promises'; -import { readFileSync } from 'fs'; -import { dirname, resolve } from 'path'; - -import { FeeOpts } from './fees.js'; -import { - parseAztecAddress, - parseBigint, - parseEthereumAddress, - parseField, - parseFieldFromHexString, - parseOptionalAztecAddress, - parseOptionalInteger, - parseOptionalLogId, - parseOptionalTxHash, - parsePartialAddress, - parsePrivateKey, - parsePublicKey, - parseTxHash, -} from './parse_args.js'; - -/** - * If we can successfully resolve 'host.docker.internal', then we are running in a container, and we should treat - * localhost as being host.docker.internal. - */ -const getLocalhost = () => - lookup('host.docker.internal') - .then(() => 'host.docker.internal') - .catch(() => 'localhost'); - -const LOCALHOST = await getLocalhost(); -const { ETHEREUM_HOST = `http://${LOCALHOST}:8545`, PRIVATE_KEY, API_KEY, CLI_VERSION } = process.env; - -class Command extends CommanderCommand { - addOptions(options: Option[]) { - options.forEach(option => this.addOption(option)); - return this; - } - - override createCommand(name?: string): Command { - return new Command(name); - } -} - -/** - * Returns commander program that defines the CLI. - * @param log - Console logger. - * @param debugLogger - Debug logger. - * @returns The CLI. - */ -export function getProgram(log: LogFn, debugLogger: DebugLogger): Command { - const program = new Command(); - - const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../package.json'); - const cliVersion: string = CLI_VERSION || JSON.parse(readFileSync(packageJsonPath).toString()).version; - const logJson = (obj: object) => log(JSON.stringify(obj, null, 2)); - - program.name('aztec-cli').description('CLI for interacting with Aztec.').version(cliVersion); - - const pxeOption = new Option('-u, --rpc-url ', 'URL of the PXE') - .env('PXE_URL') - .default(`http://${LOCALHOST}:8080`) - .makeOptionMandatory(true); - - const createPrivateKeyOption = (description: string, mandatory: boolean) => - new Option('-e, --private-key ', description) - .env('PRIVATE_KEY') - .argParser(parsePrivateKey) - .makeOptionMandatory(mandatory); - - program - .command('deploy-l1-contracts') - .description('Deploys all necessary Ethereum contracts for Aztec.') - .requiredOption( - '-u, --rpc-url ', - 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', - ETHEREUM_HOST, - ) - .option('-a, --api-key ', 'Api key for the ethereum host', API_KEY) - .requiredOption('-p, --private-key ', 'The private key to use for deployment', PRIVATE_KEY) - .option( - '-m, --mnemonic ', - 'The mnemonic to use in deployment', - 'test test test test test test test test test test test junk', - ) - .action(async options => { - const { deployL1Contracts } = await import('./cmds/deploy_l1_contracts.js'); - await deployL1Contracts( - options.rpcUrl, - options.apiKey ?? '', - options.privateKey, - options.mnemonic, - log, - debugLogger, - ); - }); - - program - .command('deploy-l1-verifier') - .description('Deploys the rollup verifier contract') - .requiredOption( - '--eth-rpc-url ', - 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', - ETHEREUM_HOST, - ) - .addOption(pxeOption) - .requiredOption('-p, --private-key ', 'The private key to use for deployment', PRIVATE_KEY) - .option( - '-m, --mnemonic ', - 'The mnemonic to use in deployment', - 'test test test test test test test test test test test junk', - ) - .requiredOption('--verifier ', 'Either mock or real', 'real') - .option('--bb ', 'Path to bb binary') - .option('--bb-working-dir ', 'Path to bb working directory') - .action(async options => { - const { deployMockVerifier, deployUltraVerifier } = await import('./cmds/deploy_l1_verifier.js'); - if (options.verifier === 'mock') { - await deployMockVerifier( - options.ethRpcUrl, - options.privateKey, - options.mnemonic, - options.rpcUrl, - log, - debugLogger, - ); - } else { - await deployUltraVerifier( - options.ethRpcUrl, - options.privateKey, - options.mnemonic, - options.rpcUrl, - options.bb, - options.bbWorkingDir, - log, - debugLogger, - ); - } - }); - - program - .command('bridge-l1-gas') - .description('Mints L1 gas tokens and pushes them to L2.') - .argument('', 'The amount of gas tokens to mint and bridge.', parseBigint) - .argument('', 'Aztec address of the recipient.', parseAztecAddress) - .requiredOption( - '--l1-rpc-url ', - 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', - ETHEREUM_HOST, - ) - .option('-a, --api-key ', 'Api key for the ethereum host', API_KEY) - .option( - '-m, --mnemonic ', - 'The mnemonic to use for deriving the Ethereum address that will mint and bridge', - 'test test test test test test test test test test test junk', - ) - .addOption(pxeOption) - .action(async (amount, recipient, options) => { - const { bridgeL1Gas } = await import('./cmds/bridge_l1_gas.js'); - await bridgeL1Gas( - amount, - recipient, - options.rpcUrl, - options.l1RpcUrl, - options.apiKey ?? '', - options.mnemonic, - log, - debugLogger, - ); - }); - - program - .command('get-l1-balance') - .description('Gets the balance of gas tokens in L1 for the given Ethereum address.') - .argument('', 'Ethereum address to check.', parseEthereumAddress) - .requiredOption( - '--l1-rpc-url ', - 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', - ETHEREUM_HOST, - ) - .option('-a, --api-key ', 'Api key for the ethereum host', API_KEY) - .addOption(pxeOption) - .action(async (who, options) => { - const { getL1Balance } = await import('./cmds/get_l1_balance.js'); - await getL1Balance(who, options.rpcUrl, options.l1RpcUrl, options.apiKey ?? '', log, debugLogger); - }); - - program - .command('generate-keys') - .summary('Generates encryption and signing private keys.') - .description('Generates and encryption and signing private key pair.') - .option( - '-m, --mnemonic', - 'An optional mnemonic string used for the private key generation. If not provided, random private key will be generated.', - ) - .action(async _options => { - const { generateKeys } = await import('./cmds/generate_private_key.js'); - const { privateEncryptionKey, privateSigningKey } = generateKeys(); - log(`Encryption Private Key: ${privateEncryptionKey}\nSigning Private key: ${privateSigningKey}\n`); - }); - - program - .command('generate-p2p-private-key') - .summary('Generates a LibP2P peer private key.') - .description('Generates a private key that can be used for running a node on a LibP2P network.') - .action(async () => { - const { generateP2PPrivateKey } = await import('./cmds/generate_p2p_private_key.js'); - await generateP2PPrivateKey(log); - }); - - program - .command('create-account') - .description( - 'Creates an aztec account that can be used for sending transactions. Registers the account on the PXE and deploys an account contract. Uses a Schnorr single-key account which uses the same key for encryption and authentication (not secure for production usage).', - ) - .summary('Creates an aztec account that can be used for sending transactions.') - .option( - '--skip-initialization', - 'Skip initializing the account contract. Useful for publicly deploying an existing account.', - ) - .option('--public-deploy', 'Publicly deploys the account and registers the class if needed.') - .addOption(createPrivateKeyOption('Private key for account. Uses random by default.', false)) - .addOption(pxeOption) - .addOptions(FeeOpts.getOptions()) - .option( - '--register-only', - 'Just register the account on the PXE. Do not deploy or initialize the account contract.', - ) - // `options.wait` is default true. Passing `--no-wait` will set it to false. - // https://github.com/tj/commander.js#other-option-types-negatable-boolean-and-booleanvalue - .option('--no-wait', 'Skip waiting for the contract to be deployed. Print the hash of deployment transaction') - .action(async args => { - const { createAccount } = await import('./cmds/create_account.js'); - const { rpcUrl, privateKey, wait, registerOnly, skipInitialization, publicDeploy } = args; - await createAccount( - rpcUrl, - privateKey, - registerOnly, - skipInitialization, - publicDeploy, - wait, - FeeOpts.fromCli(args, log), - debugLogger, - log, - ); - }); - - program - .command('bootstrap') - .description('Bootstrap the blockchain') - .addOption(pxeOption) - .action(async options => { - const { bootstrap } = await import('./cmds/bootstrap.js'); - await bootstrap(options.rpcUrl, log); - }); - - program - .command('deploy') - .description('Deploys a compiled Aztec.nr contract to Aztec.') - .argument( - '', - "A compiled Aztec.nr contract's artifact in JSON format or name of a contract artifact exported by @aztec/noir-contracts.js", - ) - .option('--initialize ', 'The contract initializer function to call', 'constructor') - .option('--no-initialize') - .option('-a, --args ', 'Contract constructor arguments', []) - .addOption(pxeOption) - .option( - '-k, --public-key ', - 'Optional encryption public key for this address. Set this value only if this contract is expected to receive private notes, which will be encrypted using this public key.', - parsePublicKey, - ) - .option( - '-s, --salt ', - 'Optional deployment salt as a hex string for generating the deployment address.', - parseFieldFromHexString, - ) - .option('--universal', 'Do not mix the sender address into the deployment.') - .addOption(createPrivateKeyOption("The sender's private key.", true)) - .option('--json', 'Emit output as json') - // `options.wait` is default true. Passing `--no-wait` will set it to false. - // https://github.com/tj/commander.js#other-option-types-negatable-boolean-and-booleanvalue - .option('--no-wait', 'Skip waiting for the contract to be deployed. Print the hash of deployment transaction') - .option('--class-registration', 'Register the contract class. Only has to be done once') - .option('--no-class-registration', 'Skip registering the contract class') - .option('--public-deployment', 'Deploy the public bytecode of contract') - .option('--no-public-deployment', "Skip deploying the contract's public bytecode") - .addOptions(FeeOpts.getOptions()) - .action(async (artifactPath, opts) => { - const { deploy } = await import('./cmds/deploy.js'); - const { - json, - rpcUrl, - publicKey, - args: rawArgs, - salt, - wait, - privateKey, - classRegistration, - initialize, - publicDeployment, - universal, - } = opts; - await deploy( - artifactPath, - json, - rpcUrl, - publicKey ? PublicKeys.fromString(publicKey) : undefined, - rawArgs, - salt, - privateKey, - typeof initialize === 'string' ? initialize : undefined, - !publicDeployment, - !classRegistration, - typeof initialize === 'string' ? false : initialize, - universal, - wait, - FeeOpts.fromCli(opts, log), - debugLogger, - log, - logJson, - ); - }); - - program - .command('add-contract') - .description( - 'Adds an existing contract to the PXE. This is useful if you have deployed a contract outside of the PXE and want to use it with the PXE.', - ) - .requiredOption( - '-c, --contract-artifact ', - "A compiled Aztec.nr contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts.js", - ) - .requiredOption('-ca, --contract-address
', 'Aztec address of the contract.', parseAztecAddress) - .requiredOption('--init-hash ', 'Initialization hash', parseFieldFromHexString) - .option('--salt ', 'Optional deployment salt', parseFieldFromHexString) - .option('-p, --public-key ', 'Optional public key for this contract', parsePublicKey) - .option('--portal-address
', 'Optional address to a portal contract on L1', parseEthereumAddress) - .option('--deployer-address
', 'Optional address of the contract deployer', parseAztecAddress) - .addOption(pxeOption) - .action(async options => { - const { addContract } = await import('./cmds/add_contract.js'); - await addContract( - options.rpcUrl, - options.contractArtifact, - options.contractAddress, - options.initHash, - options.salt ?? Fr.ZERO, - options.publicKey, - options.deployerAddress, - debugLogger, - log, - ); - }); - - program - .command('get-tx') - .description('Gets the receipt for the specified transaction hash.') - .argument('', 'A transaction hash to get the receipt for.', parseTxHash) - .addOption(pxeOption) - .action(async (txHash, options) => { - const { getTx } = await import('./cmds/get_tx.js'); - await getTx(options.rpcUrl, txHash, debugLogger, log); - }); - - program - .command('get-block') - .description('Gets info for a given block or latest.') - .argument('[blockNumber]', 'Block height', parseOptionalInteger) - .option('-f, --follow', 'Keep polling for new blocks') - .addOption(pxeOption) - .action(async (blockNumber, options) => { - const { getBlock } = await import('./cmds/get_block.js'); - await getBlock(options.rpcUrl, blockNumber, options.follow, debugLogger, log); - }); - - program - .command('get-contract-data') - .description('Gets information about the Aztec contract deployed at the specified address.') - .argument('', 'Aztec address of the contract.', parseAztecAddress) - .addOption(pxeOption) - .option('-b, --include-bytecode ', "Include the contract's public function bytecode, if any.", false) - .action(async (contractAddress, options) => { - const { getContractData } = await import('./cmds/get_contract_data.js'); - await getContractData(options.rpcUrl, contractAddress, options.includeBytecode, debugLogger, log); - }); - - program - .command('get-logs') - .description('Gets all the unencrypted logs from an intersection of all the filter params.') - .option('-tx, --tx-hash ', 'A transaction hash to get the receipt for.', parseOptionalTxHash) - .option( - '-fb, --from-block ', - 'Initial block number for getting logs (defaults to 1).', - parseOptionalInteger, - ) - .option('-tb, --to-block ', 'Up to which block to fetch logs (defaults to latest).', parseOptionalInteger) - .option('-al --after-log ', 'ID of a log after which to fetch the logs.', parseOptionalLogId) - .option('-ca, --contract-address
', 'Contract address to filter logs by.', parseOptionalAztecAddress) - .addOption(pxeOption) - .option('--follow', 'If set, will keep polling for new logs until interrupted.') - .action(async ({ txHash, fromBlock, toBlock, afterLog, contractAddress, rpcUrl, follow }) => { - const { getLogs } = await import('./cmds/get_logs.js'); - await getLogs(txHash, fromBlock, toBlock, afterLog, contractAddress, rpcUrl, follow, debugLogger, log); - }); - - program - .command('register-recipient') - .description('Register a recipient in the PXE.') - .requiredOption('-a, --address ', "The account's Aztec address.", parseAztecAddress) - .requiredOption('-p, --public-key ', 'The account public key.', parsePublicKey) - .requiredOption( - '-pa, --partial-address ', - 'The partially computed address of the account contract.', - parsePartialAddress, - ) - .addOption(pxeOption) - .action(async ({ address, publicKey, partialAddress, rpcUrl }) => { - const { registerRecipient } = await import('./cmds/register_recipient.js'); - await registerRecipient(address, publicKey, partialAddress, rpcUrl, debugLogger, log); - }); - - program - .command('get-accounts') - .description('Gets all the Aztec accounts stored in the PXE.') - .addOption(pxeOption) - .option('--json', 'Emit output as json') - .action(async (options: any) => { - const { getAccounts } = await import('./cmds/get_accounts.js'); - await getAccounts(options.rpcUrl, options.json, debugLogger, log, logJson); - }); - - program - .command('get-account') - .description('Gets an account given its Aztec address.') - .argument('
', 'The Aztec address to get account for', parseAztecAddress) - .addOption(pxeOption) - .action(async (address, options) => { - const { getAccount } = await import('./cmds/get_account.js'); - await getAccount(address, options.rpcUrl, debugLogger, log); - }); - - program - .command('get-recipients') - .description('Gets all the recipients stored in the PXE.') - .addOption(pxeOption) - .action(async (options: any) => { - const { getRecipients } = await import('./cmds/get_recipients.js'); - await getRecipients(options.rpcUrl, debugLogger, log); - }); - - program - .command('get-recipient') - .description('Gets a recipient given its Aztec address.') - .argument('
', 'The Aztec address to get recipient for', parseAztecAddress) - .addOption(pxeOption) - .action(async (address, options) => { - const { getRecipient } = await import('./cmds/get_recipient.js'); - await getRecipient(address, options.rpcUrl, debugLogger, log); - }); - - program - .command('get-balance') - .description('Gets the token balance for an account. Does NOT format according to decimals.') - .argument('
', 'Aztec address to query balance for.', parseAztecAddress) - .option('-t, --token-address
', 'Token address to query balance for (defaults to gas token).') - .addOption(pxeOption) - .action(async (address, options) => { - const { getBalance } = await import('./cmds/get_balance.js'); - await getBalance(address, options.tokenAddress, options.rpcUrl, debugLogger, log); - }); - - program - .command('send') - .description('Calls a function on an Aztec contract.') - .argument('', 'Name of function to execute') - .option('-a, --args [functionArgs...]', 'Function arguments', []) - .requiredOption( - '-c, --contract-artifact ', - "A compiled Aztec.nr contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts.js", - ) - .requiredOption('-ca, --contract-address
', 'Aztec address of the contract.', parseAztecAddress) - .addOption(createPrivateKeyOption("The sender's private key.", true)) - .addOption(pxeOption) - .option('--no-wait', 'Print transaction hash without waiting for it to be mined') - .addOptions(FeeOpts.getOptions()) - .action(async (functionName, options) => { - const { send } = await import('./cmds/send.js'); - await send( - functionName, - options.args, - options.contractArtifact, - options.contractAddress, - options.privateKey, - options.rpcUrl, - !options.noWait, - FeeOpts.fromCli(options, log), - debugLogger, - log, - ); - }); - - program - .command('call') - .description( - 'Simulates the execution of a view (read-only) function on a deployed contract, without modifying state.', - ) - .argument('', 'Name of function to call') - .option('-a, --args [functionArgs...]', 'Function arguments', []) - .requiredOption( - '-c, --contract-artifact ', - "A compiled Aztec.nr contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts.js", - ) - .requiredOption('-ca, --contract-address
', 'Aztec address of the contract.', parseAztecAddress) - .option('-f, --from ', 'Aztec address of the caller. If empty, will use the first account from RPC.') - .addOption(pxeOption) - .action(async (functionName, options) => { - const { call } = await import('./cmds/call.js'); - await call( - functionName, - options.args, - options.contractArtifact, - options.contractAddress, - options.from, - options.rpcUrl, - debugLogger, - log, - ); - }); - - program - .command('add-note') - .description('Adds a note to the database in the PXE.') - .argument('
', 'The Aztec address of the note owner.', parseAztecAddress) - .argument('', 'Aztec address of the contract.', parseAztecAddress) - .argument('', 'The storage slot of the note.', parseField) - .argument('', 'The type ID of the note.', parseField) - .argument('', 'The tx hash of the tx containing the note.', parseTxHash) - .requiredOption('-n, --note [note...]', 'The members of a Note serialized as hex strings.', []) - .addOption(pxeOption) - .action(async (address, contractAddress, storageSlot, noteTypeId, txHash, options) => { - const { addNote } = await import('./cmds/add_note.js'); - await addNote( - address, - contractAddress, - storageSlot, - noteTypeId, - txHash, - options.note, - options.rpcUrl, - debugLogger, - ); - }); - - program - .command('add-pending-shield') - .description('Adds a pending shield note to the database in the PXE.') - .argument('
', 'Aztec address of the note owner.', parseAztecAddress) - .argument('', 'Amount of the pending shield note.', parseBigint) - .requiredOption('-ca, --contract-address
', 'Aztec address of the token contract.', parseAztecAddress) - .requiredOption('-tx, --tx-hash ', 'Tx hash in which the note was created.', parseOptionalTxHash) - .requiredOption('--secret ', 'Secret used for shielding the note.', parseField) - .addOption(pxeOption) - .action(async (address, amount, options) => { - const { addPendingShield } = await import('./cmds/add_pending_shield.js'); - await addPendingShield( - address, - options.contractAddress, - amount, - options.secret, - options.txHash, - options.rpcUrl, - debugLogger, - log, - ); - }); - - // Helper for users to decode hex strings into structs if needed. - program - .command('parse-parameter-struct') - .description("Helper for parsing an encoded string into a contract's parameter struct.") - .argument('', 'The encoded hex string') - .requiredOption( - '-c, --contract-artifact ', - "A compiled Aztec.nr contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts.js", - ) - .requiredOption('-p, --parameter ', 'The name of the struct parameter to decode into') - .action(async (encodedString, options) => { - const { parseParameterStruct } = await import('./cmds/parse_parameter_struct.js'); - await parseParameterStruct(encodedString, options.contractArtifact, options.parameter, log); - }); - - program - .command('block-number') - .description('Gets the current Aztec L2 block number.') - .addOption(pxeOption) - .action(async (options: any) => { - const { blockNumber } = await import('./cmds/block_number.js'); - await blockNumber(options.rpcUrl, debugLogger, log); - }); - - program - .command('example-contracts') - .description('Lists the example contracts available to deploy from @aztec/noir-contracts.js') - .action(async () => { - const { exampleContracts } = await import('./cmds/example_contracts.js'); - await exampleContracts(log); - }); - - program - .command('get-node-info') - .description('Gets the information of an aztec node at a URL.') - .addOption(pxeOption) - .action(async options => { - const { getNodeInfo } = await import('./cmds/get_node_info.js'); - await getNodeInfo(options.rpcUrl, debugLogger, log); - }); - - program - .command('get-pxe-info') - .description('Gets the information of a PXE at a URL.') - .addOption(pxeOption) - .action(async options => { - const { getPXEInfo } = await import('./cmds/get_pxe_info.js'); - await getPXEInfo(options.rpcUrl, debugLogger, log); - }); - - program - .command('inspect-contract') - .description('Shows list of external callable functions for a contract') - .argument( - '', - `A compiled Noir contract's artifact in JSON format or name of a contract artifact exported by @aztec/noir-contracts.js`, - ) - .action(async (contractArtifactFile: string) => { - const { inspectContract } = await import('./cmds/inspect_contract.js'); - await inspectContract(contractArtifactFile, debugLogger, log); - }); - - program - .command('compute-selector') - .description('Given a function signature, it computes a selector') - .argument('', 'Function signature to compute selector for e.g. foo(Field)') - .action(async (functionSignature: string) => { - const { computeSelector } = await import('./cmds/compute_selector.js'); - computeSelector(functionSignature, log); - }); - - program - .command('sequencers') - .argument('', 'Command to run: list, add, remove, who-next') - .argument('[who]', 'Who to add/remove') - .description('Manages or queries registered sequencers on the L1 rollup contract.') - .requiredOption( - '--l1-rpc-url ', - 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', - ETHEREUM_HOST, - ) - .option('-a, --api-key ', 'Api key for the ethereum host', API_KEY) - .option( - '-m, --mnemonic ', - 'The mnemonic for the sender of the tx', - 'test test test test test test test test test test test junk', - ) - .option('--block-number ', 'Block number to query next sequencer for', parseOptionalInteger) - .addOption(pxeOption) - .action(async (command, who, options) => { - const { sequencers } = await import('./cmds/sequencers.js'); - await sequencers({ - command: command, - who, - mnemonic: options.mnemonic, - rpcUrl: options.rpcUrl, - l1RpcUrl: options.l1RpcUrl, - apiKey: options.apiKey ?? '', - blockNumber: options.blockNumber, - log, - debugLogger, - }); - }); - - return program; -} diff --git a/yarn-project/cli/src/utils.ts b/yarn-project/cli/src/utils/aztec.ts similarity index 74% rename from yarn-project/cli/src/utils.ts rename to yarn-project/cli/src/utils/aztec.ts index 0d8d714d533..6a7c22f1c83 100644 --- a/yarn-project/cli/src/utils.ts +++ b/yarn-project/cli/src/utils/aztec.ts @@ -1,25 +1,13 @@ import { type ContractArtifact, type FunctionArtifact, loadContractArtifact } from '@aztec/aztec.js/abi'; -import { AztecAddress } from '@aztec/aztec.js/aztec_address'; import { type L1ContractArtifactsForDeployment } from '@aztec/aztec.js/ethereum'; -import { type PXE } from '@aztec/aztec.js/interfaces/pxe'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; import { type NoirPackageConfig } from '@aztec/foundation/noir'; -import { - AvailabilityOracleAbi, - AvailabilityOracleBytecode, - GasPortalAbi, - GasPortalBytecode, - PortalERC20Abi, - PortalERC20Bytecode, -} from '@aztec/l1-artifacts'; -import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types'; import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token'; import TOML from '@iarna/toml'; -import { CommanderError, InvalidArgumentError } from 'commander'; -import { readFile, rename, writeFile } from 'fs/promises'; +import { readFile } from 'fs/promises'; -import { encodeArgs } from './encoding.js'; +import { encodeArgs } from '../encoding.js'; /** * Helper type to dynamically import contracts. @@ -65,6 +53,12 @@ export async function deployAztecContracts( RegistryBytecode, RollupAbi, RollupBytecode, + AvailabilityOracleAbi, + AvailabilityOracleBytecode, + GasPortalAbi, + GasPortalBytecode, + PortalERC20Abi, + PortalERC20Bytecode, } = await import('@aztec/l1-artifacts'); const { createEthereumChain, deployL1Contracts } = await import('@aztec/ethereum'); const { mnemonicToAccount, privateKeyToAccount } = await import('viem/accounts'); @@ -103,6 +97,8 @@ export async function deployAztecContracts( contractBytecode: GasPortalBytecode, }, }; + const { getVKTreeRoot } = await import('@aztec/noir-protocol-circuits-types'); + return await deployL1Contracts(chain.rpcUrl, account, chain.chainInfo, debugLogger, l1Artifacts, { l2GasTokenAddress: GasTokenAddress, vkTreeRoot: getVKTreeRoot(), @@ -114,6 +110,8 @@ export async function deployAztecContracts( * @returns The contract ABIs. */ export async function getExampleContractArtifacts(): Promise { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore - Importing noir-contracts.js even in devDeps results in a circular dependency error. Need to ignore because this line doesn't cause an error in a dev environment const imports = await import('@aztec/noir-contracts.js'); return Object.fromEntries(Object.entries(imports).filter(([key]) => key.endsWith('Artifact'))) as any; } @@ -147,31 +145,6 @@ export async function getContractArtifact(fileDir: string, log: LogFn) { } } -/** - * Utility to select a TX sender either from user input - * or from the first account that is found in a PXE instance. - * @param pxe - The PXE instance that will be checked for an account. - * @param _from - The user input. - * @returns An Aztec address. Will throw if one can't be found in either options. - */ -export async function getTxSender(pxe: PXE, _from?: string) { - let from: AztecAddress; - if (_from) { - try { - from = AztecAddress.fromString(_from); - } catch { - throw new InvalidArgumentError(`Invalid option 'from' passed: ${_from}`); - } - } else { - const accounts = await pxe.getRegisteredAccounts(); - if (!accounts.length) { - throw new Error('No accounts found in PXE instance.'); - } - from = accounts[0].address; - } - return from; -} - /** * Performs necessary checks, conversions & operations to call a contract fn from the CLI. * @param contractFile - Directory of the compiled contract ABI. @@ -200,34 +173,6 @@ export const stripLeadingHex = (hex: string) => { return hex; }; -/** - * Updates a file in place atomically. - * @param filePath - Path to file - * @param contents - New contents to write - */ -export async function atomicUpdateFile(filePath: string, contents: string) { - const tmpFilepath = filePath + '.tmp'; - try { - await writeFile(tmpFilepath, contents, { - // let's crash if the tmp file already exists - flag: 'wx', - }); - await rename(tmpFilepath, filePath); - } catch (e) { - if (e instanceof Error && 'code' in e && e.code === 'EEXIST') { - const commanderError = new CommanderError( - 1, - e.code, - `Temporary file already exists: ${tmpFilepath}. Delete this file and try again.`, - ); - commanderError.nestedError = e.message; - throw commanderError; - } else { - throw e; - } - } -} - /** * Pretty prints Nargo.toml contents to a string * @param config - Nargo.toml contents diff --git a/yarn-project/cli/src/parse_args.ts b/yarn-project/cli/src/utils/commands.ts similarity index 70% rename from yarn-project/cli/src/parse_args.ts rename to yarn-project/cli/src/utils/commands.ts index d4b49c8cc16..52f191c9e6c 100644 --- a/yarn-project/cli/src/parse_args.ts +++ b/yarn-project/cli/src/utils/commands.ts @@ -4,9 +4,96 @@ import { EthAddress } from '@aztec/aztec.js/eth_address'; import { Fr } from '@aztec/aztec.js/fields'; import { LogId } from '@aztec/aztec.js/log_id'; import { TxHash } from '@aztec/aztec.js/tx_hash'; +import { type PXE } from '@aztec/circuit-types'; import { PublicKeys } from '@aztec/circuits.js'; +import { type LogFn } from '@aztec/foundation/log'; -import { InvalidArgumentError } from 'commander'; +import { type Command, CommanderError, InvalidArgumentError, Option } from 'commander'; +import { lookup } from 'dns/promises'; +import { rename, writeFile } from 'fs/promises'; + +/** + * If we can successfully resolve 'host.docker.internal', then we are running in a container, and we should treat + * localhost as being host.docker.internal. + */ +export const getLocalhost = () => + lookup('host.docker.internal') + .then(() => 'host.docker.internal') + .catch(() => 'localhost'); + +export const LOCALHOST = await getLocalhost(); +export const { ETHEREUM_HOST = `http://${LOCALHOST}:8545`, PRIVATE_KEY, API_KEY, CLI_VERSION } = process.env; + +export function addOptions(program: Command, options: Option[]) { + options.forEach(option => program.addOption(option)); + return program; +} + +export const pxeOption = new Option('-u, --rpc-url ', 'URL of the PXE') + .env('PXE_URL') + .default(`http://${LOCALHOST}:8080`) + .makeOptionMandatory(true); + +export const createPrivateKeyOption = (description: string, mandatory: boolean) => + new Option('-e, --private-key ', description) + .env('PRIVATE_KEY') + .argParser(parsePrivateKey) + .makeOptionMandatory(mandatory); + +export const logJson = (log: LogFn) => (obj: object) => log(JSON.stringify(obj, null, 2)); + +/** + * Updates a file in place atomically. + * @param filePath - Path to file + * @param contents - New contents to write + */ +export async function atomicUpdateFile(filePath: string, contents: string) { + const tmpFilepath = filePath + '.tmp'; + try { + await writeFile(tmpFilepath, contents, { + // let's crash if the tmp file already exists + flag: 'wx', + }); + await rename(tmpFilepath, filePath); + } catch (e) { + if (e instanceof Error && 'code' in e && e.code === 'EEXIST') { + const commanderError = new CommanderError( + 1, + e.code, + `Temporary file already exists: ${tmpFilepath}. Delete this file and try again.`, + ); + commanderError.nestedError = e.message; + throw commanderError; + } else { + throw e; + } + } +} + +/** + * Utility to select a TX sender either from user input + * or from the first account that is found in a PXE instance. + * @param pxe - The PXE instance that will be checked for an account. + * @param _from - The user input. + * @returns An Aztec address. Will throw if one can't be found in either options. + */ +export async function getTxSender(pxe: PXE, _from?: string) { + let from: AztecAddress; + if (_from) { + try { + from = AztecAddress.fromString(_from); + } catch { + throw new InvalidArgumentError(`Invalid option 'from' passed: ${_from}`); + } + } else { + const accounts = await pxe.getRegisteredAccounts(); + if (!accounts.length) { + throw new Error('No accounts found in PXE instance.'); + } + from = accounts[0].address; + } + return from; +} /** * Removes the leading 0x from a hex string. If no leading 0x is found the string is returned unchanged. diff --git a/yarn-project/cli/tsconfig.json b/yarn-project/cli/tsconfig.json index 0627dbf0496..69a3c280d81 100644 --- a/yarn-project/cli/tsconfig.json +++ b/yarn-project/cli/tsconfig.json @@ -6,44 +6,32 @@ "tsBuildInfoFile": ".tsbuildinfo" }, "references": [ - { - "path": "../accounts" - }, { "path": "../aztec.js" }, - { - "path": "../bb-prover" - }, { "path": "../circuit-types" }, - { - "path": "../circuits.js" - }, - { - "path": "../ethereum" - }, { "path": "../foundation" }, { - "path": "../l1-artifacts" + "path": "../types" }, { - "path": "../noir-contracts.js" + "path": "../accounts" }, { - "path": "../noir-protocol-circuits-types" + "path": "../circuits.js" }, { - "path": "../protocol-contracts" + "path": "../ethereum" }, { - "path": "../simulator" + "path": "../l1-artifacts" }, { - "path": "../types" + "path": "../protocol-contracts" } ], "include": ["src"], diff --git a/yarn-project/end-to-end/scripts/docker-compose.yml b/yarn-project/end-to-end/scripts/docker-compose.yml index fba311890c4..06f72f221c4 100644 --- a/yarn-project/end-to-end/scripts/docker-compose.yml +++ b/yarn-project/end-to-end/scripts/docker-compose.yml @@ -15,6 +15,7 @@ services: sandbox: image: aztecprotocol/aztec:${AZTEC_DOCKER_TAG:-latest} + command: 'start --sandbox' environment: DEBUG: 'aztec:*' DEBUG_COLORS: 1 diff --git a/yarn-project/noir-protocol-circuits-types/package.json b/yarn-project/noir-protocol-circuits-types/package.json index 85546842b68..c33e8ba46eb 100644 --- a/yarn-project/noir-protocol-circuits-types/package.json +++ b/yarn-project/noir-protocol-circuits-types/package.json @@ -54,7 +54,6 @@ ] }, "dependencies": { - "@aztec/builder": "workspace:^", "@aztec/circuits.js": "workspace:^", "@aztec/foundation": "workspace:^", "@aztec/types": "workspace:^", diff --git a/yarn-project/noir-protocol-circuits-types/tsconfig.json b/yarn-project/noir-protocol-circuits-types/tsconfig.json index 37b2a2bf779..4544ee09c62 100644 --- a/yarn-project/noir-protocol-circuits-types/tsconfig.json +++ b/yarn-project/noir-protocol-circuits-types/tsconfig.json @@ -7,9 +7,6 @@ "resolveJsonModule": true }, "references": [ - { - "path": "../builder" - }, { "path": "../circuits.js" }, @@ -26,5 +23,5 @@ "path": "../merkle-tree" } ], - "include": ["src", "artifacts/*.d.json.ts", "artifacts/**/*.d.json.ts", ] + "include": ["src", "artifacts/*.d.json.ts", "artifacts/**/*.d.json.ts"] } diff --git a/yarn-project/package.json b/yarn-project/package.json index f9a72eb8eea..b395389b5cb 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -25,6 +25,7 @@ "aztec-faucet", "aztec-node", "bb-prover", + "builder", "pxe", "aztec", "aztec.js", @@ -40,7 +41,6 @@ "kv-store", "l1-artifacts", "merkle-tree", - "builder", "noir-contracts.js", "noir-protocol-circuits-types", "p2p", diff --git a/yarn-project/prover-client/package.json b/yarn-project/prover-client/package.json index 04cc3185a95..afb8851498c 100644 --- a/yarn-project/prover-client/package.json +++ b/yarn-project/prover-client/package.json @@ -68,7 +68,7 @@ "@aztec/telemetry-client": "workspace:^", "@aztec/world-state": "workspace:^", "@noir-lang/types": "portal:../../noir/packages/types", - "commander": "^9.0.0", + "commander": "^12.1.0", "lodash.chunk": "^4.2.0", "source-map-support": "^0.5.21", "tslib": "^2.4.0" diff --git a/yarn-project/txe/src/bin/index.ts b/yarn-project/txe/src/bin/index.ts index f46cd541c95..9660ff972b6 100644 --- a/yarn-project/txe/src/bin/index.ts +++ b/yarn-project/txe/src/bin/index.ts @@ -1,81 +1,24 @@ #!/usr/bin/env -S node --no-warnings -import { Fr } from '@aztec/foundation/fields'; -import { JsonRpcServer } from '@aztec/foundation/json-rpc/server'; -import { type Logger, createDebugLogger } from '@aztec/foundation/log'; +import { createDebugLogger } from '@aztec/aztec.js'; import http from 'http'; -import { TXEService } from '../txe_service/txe_service.js'; -import { type ForeignCallResult, toForeignCallResult } from '../util/encoding.js'; - -const { TXE_PORT = 8080 } = process.env; - -const logger = createDebugLogger('aztec:txe_service'); - -const TXESessions = new Map(); - -type MethodNames = { - [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never; -}[keyof T]; - -type TXEForeignCallInput = { - session_id: number; - function: MethodNames | 'reset'; - inputs: any[]; -}; - -class TXEDispatcher { - constructor(private logger: Logger) {} - - // eslint-disable-next-line camelcase - async resolve_foreign_call({ - session_id: sessionId, - function: functionName, - inputs, - }: TXEForeignCallInput): Promise { - this.logger.debug(`Calling ${functionName} on session ${sessionId}`); - - if (!TXESessions.has(sessionId) && functionName != 'reset') { - this.logger.info(`Creating new session ${sessionId}`); - TXESessions.set(sessionId, await TXEService.init(logger)); - } - - if (functionName === 'reset') { - TXESessions.delete(sessionId) && - this.logger.info(`Called reset on session ${sessionId}, yeeting it out of existence`); - return toForeignCallResult([]); - } else { - const txeService = TXESessions.get(sessionId); - const response = await (txeService as any)[functionName](...inputs); - return response; - } - } -} - -/** - * Creates an http server that forwards calls to the TXE and starts it on the given port. - * @param txeService - TXE that answers queries to the created HTTP server. - * @param port - Port to listen in. - * @returns A running http server. - */ -export function startTXEHttpServer(dispatcher: TXEDispatcher, port: string | number): http.Server { - const txeServer = new JsonRpcServer(dispatcher, { Fr }, {}, ['init']); - - const app = txeServer.getApp(); - const httpServer = http.createServer(app.callback()); - httpServer.timeout = 1e3 * 60 * 5; // 5 minutes - httpServer.listen(port); - - return httpServer; -} +import { createTXERpcServer } from '../index.js'; /** * Create and start a new TXE HTTP Server */ function main() { + const { TXE_PORT = 8080 } = process.env; + + const logger = createDebugLogger('aztec:txe_service'); logger.info(`Setting up TXE...`); - startTXEHttpServer(new TXEDispatcher(logger), TXE_PORT); + const txeServer = createTXERpcServer(logger); + const app = txeServer.getApp(); + const httpServer = http.createServer(app.callback()); + httpServer.timeout = 1e3 * 60 * 5; // 5 minutes + httpServer.listen(TXE_PORT); logger.info(`TXE listening on port ${TXE_PORT}`); } diff --git a/yarn-project/txe/src/index.ts b/yarn-project/txe/src/index.ts new file mode 100644 index 00000000000..4bd804b1332 --- /dev/null +++ b/yarn-project/txe/src/index.ts @@ -0,0 +1,55 @@ +import { Fr } from '@aztec/foundation/fields'; +import { JsonRpcServer } from '@aztec/foundation/json-rpc/server'; +import { type Logger } from '@aztec/foundation/log'; + +import { TXEService } from './txe_service/txe_service.js'; +import { type ForeignCallResult, toForeignCallResult } from './util/encoding.js'; + +const TXESessions = new Map(); + +type MethodNames = { + [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never; +}[keyof T]; + +type TXEForeignCallInput = { + session_id: number; + function: MethodNames | 'reset'; + inputs: any[]; +}; + +class TXEDispatcher { + constructor(private logger: Logger) {} + + // eslint-disable-next-line camelcase + async resolve_foreign_call({ + session_id: sessionId, + function: functionName, + inputs, + }: TXEForeignCallInput): Promise { + this.logger.debug(`Calling ${functionName} on session ${sessionId}`); + + if (!TXESessions.has(sessionId) && functionName != 'reset') { + this.logger.info(`Creating new session ${sessionId}`); + TXESessions.set(sessionId, await TXEService.init(this.logger)); + } + + if (functionName === 'reset') { + TXESessions.delete(sessionId) && + this.logger.info(`Called reset on session ${sessionId}, yeeting it out of existence`); + return toForeignCallResult([]); + } else { + const txeService = TXESessions.get(sessionId); + const response = await (txeService as any)[functionName](...inputs); + return response; + } + } +} + +/** + * Creates an RPC server that forwards calls to the TXE. + * @param logger - Logger to output to + * @returns A TXE RPC server. + */ +export function createTXERpcServer(logger: Logger) { + return new JsonRpcServer(new TXEDispatcher(logger), { Fr }, {}, ['init']); +} diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 7349aebceeb..244cd7ec0fa 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -197,6 +197,7 @@ __metadata: "@aztec/builder": "workspace:^" "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" + "@aztec/cli": "workspace:^" "@aztec/entrypoints": "workspace:^" "@aztec/ethereum": "workspace:^" "@aztec/foundation": "workspace:^" @@ -210,11 +211,12 @@ __metadata: "@aztec/prover-client": "workspace:^" "@aztec/pxe": "workspace:^" "@aztec/telemetry-client": "workspace:^" + "@aztec/txe": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0 "@types/koa": ^2.13.6 abitype: ^0.8.11 - commander: ^11.1.0 + commander: ^12.1.0 jest: ^29.5.0 koa: ^2.14.2 koa-router: ^12.0.0 @@ -246,7 +248,7 @@ __metadata: "@types/memdown": ^3.0.0 "@types/node": ^18.7.23 "@types/source-map-support": ^0.5.10 - commander: ^9.0.0 + commander: ^12.1.0 jest: ^29.5.0 jest-mock-extended: ^3.0.3 source-map-support: ^0.5.21 @@ -275,31 +277,15 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/builder@workspace:builder" dependencies: - "@aztec/circuits.js": "workspace:^" + "@aztec/cli": "workspace:^" "@aztec/foundation": "workspace:^" - "@aztec/types": "workspace:^" - "@iarna/toml": ^2.2.5 "@jest/globals": ^29.5.0 - "@types/fs-extra": ^11.0.1 "@types/jest": ^29.5.0 - "@types/lodash.camelcase": ^4.3.7 - "@types/lodash.capitalize": ^4.2.7 "@types/node": ^18.7.23 - "@types/pako": ^2.0.0 - "@types/semver": ^7.5.4 - base64-js: ^1.5.1 - commander: ^9.0.0 - fs-extra: ^11.1.1 + commander: ^12.1.0 jest: ^29.5.0 - lodash.camelcase: ^4.3.0 - lodash.capitalize: ^4.2.1 - memfs: ^4.6.0 - pako: ^2.1.0 - semver: ^7.5.4 ts-node: ^10.9.1 - tslib: ^2.4.0 typescript: ^5.0.4 - unzipit: ^1.4.3 bin: aztec-builder: dest/cli.js languageName: unknown @@ -352,22 +338,18 @@ __metadata: languageName: unknown linkType: soft -"@aztec/cli@workspace:cli": +"@aztec/cli@workspace:^, @aztec/cli@workspace:cli": version: 0.0.0-use.local resolution: "@aztec/cli@workspace:cli" dependencies: "@aztec/accounts": "workspace:^" "@aztec/aztec.js": "workspace:^" - "@aztec/bb-prover": "workspace:^" "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" "@aztec/ethereum": "workspace:^" "@aztec/foundation": "workspace:^" "@aztec/l1-artifacts": "workspace:^" - "@aztec/noir-contracts.js": "workspace:^" - "@aztec/noir-protocol-circuits-types": "workspace:^" "@aztec/protocol-contracts": "workspace:^" - "@aztec/simulator": "workspace:^" "@aztec/types": "workspace:^" "@iarna/toml": ^2.2.5 "@jest/globals": ^29.5.0 @@ -378,12 +360,9 @@ __metadata: "@types/semver": ^7.5.2 "@types/source-map-support": ^0.5.10 axios: ^1.7.2 - commander: ^9.0.0 + commander: ^12.1.0 jest: ^29.5.0 jest-mock-extended: ^3.0.5 - jszip: ^3.10.1 - lodash.startcase: ^4.4.0 - node-fetch: ^3.3.2 semver: ^7.5.4 solc: ^0.8.26 source-map-support: ^0.5.21 @@ -392,8 +371,15 @@ __metadata: tslib: ^2.4.0 typescript: ^5.0.4 viem: ^2.7.15 - bin: - aztec-cli: ./dest/bin/index.js + peerDependencies: + "@aztec/accounts": "workspace:^" + "@aztec/bb-prover": "workspace:^" + "@aztec/circuits.js": "workspace:^" + "@aztec/ethereum": "workspace:^" + "@aztec/l1-artifacts": "workspace:^" + "@aztec/noir-contracts.js": "workspace:^" + "@aztec/noir-protocol-circuits-types": "workspace:^" + "@aztec/protocol-contracts": "workspace:^" languageName: unknown linkType: soft @@ -661,7 +647,6 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/noir-protocol-circuits-types@workspace:noir-protocol-circuits-types" dependencies: - "@aztec/builder": "workspace:^" "@aztec/circuits.js": "workspace:^" "@aztec/foundation": "workspace:^" "@aztec/kv-store": "workspace:^" @@ -791,7 +776,7 @@ __metadata: "@types/memdown": ^3.0.0 "@types/node": ^18.7.23 "@types/source-map-support": ^0.5.10 - commander: ^9.0.0 + commander: ^12.1.0 jest: ^29.5.0 jest-mock-extended: ^3.0.3 lodash.chunk: ^4.2.0 @@ -966,7 +951,7 @@ __metadata: languageName: unknown linkType: soft -"@aztec/txe@workspace:txe": +"@aztec/txe@workspace:^, @aztec/txe@workspace:txe": version: 0.0.0-use.local resolution: "@aztec/txe@workspace:txe" dependencies: @@ -2232,38 +2217,6 @@ __metadata: languageName: node linkType: hard -"@jsonjoy.com/base64@npm:^1.1.1": - version: 1.1.2 - resolution: "@jsonjoy.com/base64@npm:1.1.2" - peerDependencies: - tslib: 2 - checksum: 00dbf9cbc6ecb3af0e58288a305cc4ee3dfca9efa24443d98061756e8f6de4d6d2d3764bdfde07f2b03e6ce56db27c8a59b490bd134bf3d8122b4c6b394c7010 - languageName: node - linkType: hard - -"@jsonjoy.com/json-pack@npm:^1.0.3": - version: 1.0.4 - resolution: "@jsonjoy.com/json-pack@npm:1.0.4" - dependencies: - "@jsonjoy.com/base64": ^1.1.1 - "@jsonjoy.com/util": ^1.1.2 - hyperdyperid: ^1.2.0 - thingies: ^1.20.0 - peerDependencies: - tslib: 2 - checksum: 21e5166d5b5f4856791c2c7019dfba0e8313d2501937543691cdffd5fbe1f9680548a456d2c8aa78929aa69b2ac4c787ca8dbc7cf8e4926330decedcd0d9b8ea - languageName: node - linkType: hard - -"@jsonjoy.com/util@npm:^1.1.2": - version: 1.1.3 - resolution: "@jsonjoy.com/util@npm:1.1.3" - peerDependencies: - tslib: 2 - checksum: 144df56aafcae8984d43ebf0f2a11cecb69052286c83522758823710fbf2caabbe93946bdf5c343d3b50073bb0a1c332fea0e797eb8b4df35db480a75b0946ac - languageName: node - linkType: hard - "@koa/cors@npm:^5.0.0": version: 5.0.0 resolution: "@koa/cors@npm:5.0.0" @@ -3845,7 +3798,7 @@ __metadata: languageName: node linkType: hard -"@types/fs-extra@npm:^11.0.1, @types/fs-extra@npm:^11.0.2": +"@types/fs-extra@npm:^11.0.2": version: 11.0.4 resolution: "@types/fs-extra@npm:11.0.4" dependencies: @@ -4061,24 +4014,6 @@ __metadata: languageName: node linkType: hard -"@types/lodash.camelcase@npm:^4.3.7": - version: 4.3.9 - resolution: "@types/lodash.camelcase@npm:4.3.9" - dependencies: - "@types/lodash": "*" - checksum: f54132d38ffa72b25bce2111e4d28f339599f6d4fcfc1248a89d1d96445512d7a431f0b0e74f6e6c8d6bc09fe53cf94d9426e188d8feacb3ffe04cd9c3a602e7 - languageName: node - linkType: hard - -"@types/lodash.capitalize@npm:^4.2.7": - version: 4.2.9 - resolution: "@types/lodash.capitalize@npm:4.2.9" - dependencies: - "@types/lodash": "*" - checksum: 54a9154b2084392986646335d5ed4902a89c24ce675cf8b8cfcd022f6a0eed71c30c2f8cc4b2682cfc5c55a5e1fdad2340609ba58db451dfdd41d82b14c88995 - languageName: node - linkType: hard - "@types/lodash.chunk@npm:^4.2.7, @types/lodash.chunk@npm:^4.2.9": version: 4.2.9 resolution: "@types/lodash.chunk@npm:4.2.9" @@ -4284,7 +4219,7 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:^7.5.0, @types/semver@npm:^7.5.2, @types/semver@npm:^7.5.4": +"@types/semver@npm:^7.5.0, @types/semver@npm:^7.5.2": version: 7.5.8 resolution: "@types/semver@npm:7.5.8" checksum: ea6f5276f5b84c55921785a3a27a3cd37afee0111dfe2bcb3e03c31819c197c782598f17f0b150a69d453c9584cd14c4c4d7b9a55d2c5e6cacd4d66fdb3b3663 @@ -5424,7 +5359,7 @@ __metadata: languageName: node linkType: hard -"base64-js@npm:^1.3.1, base64-js@npm:^1.5.1": +"base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 @@ -6056,10 +5991,10 @@ __metadata: languageName: node linkType: hard -"commander@npm:^11.1.0": - version: 11.1.0 - resolution: "commander@npm:11.1.0" - checksum: fd1a8557c6b5b622c89ecdfde703242ab7db3b628ea5d1755784c79b8e7cb0d74d65b4a262289b533359cd58e1bfc0bf50245dfbcd2954682a6f367c828b79ef +"commander@npm:^12.1.0": + version: 12.1.0 + resolution: "commander@npm:12.1.0" + checksum: 68e9818b00fc1ed9cdab9eb16905551c2b768a317ae69a5e3c43924c2b20ac9bb65b27e1cab36aeda7b6496376d4da908996ba2c0b5d79463e0fb1e77935d514 languageName: node linkType: hard @@ -6084,7 +6019,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^9.0.0, commander@npm:^9.5.0": +"commander@npm:^9.5.0": version: 9.5.0 resolution: "commander@npm:9.5.0" checksum: c7a3e27aa59e913b54a1bafd366b88650bc41d6651f0cbe258d4ff09d43d6a7394232a4dadd0bf518b3e696fdf595db1028a0d82c785b88bd61f8a440cecfade @@ -6356,13 +6291,6 @@ __metadata: languageName: node linkType: hard -"data-uri-to-buffer@npm:^4.0.0": - version: 4.0.1 - resolution: "data-uri-to-buffer@npm:4.0.1" - checksum: 0d0790b67ffec5302f204c2ccca4494f70b4e2d940fea3d36b09f0bb2b8539c2e86690429eb1f1dc4bcc9e4df0644193073e63d9ee48ac9fce79ec1506e4aa4c - languageName: node - linkType: hard - "data-uri-to-buffer@npm:^6.0.2": version: 6.0.2 resolution: "data-uri-to-buffer@npm:6.0.2" @@ -7810,16 +7738,6 @@ __metadata: languageName: node linkType: hard -"fetch-blob@npm:^3.1.2, fetch-blob@npm:^3.1.4": - version: 3.2.0 - resolution: "fetch-blob@npm:3.2.0" - dependencies: - node-domexception: ^1.0.0 - web-streams-polyfill: ^3.0.3 - checksum: f19bc28a2a0b9626e69fd7cf3a05798706db7f6c7548da657cbf5026a570945f5eeaedff52007ea35c8bcd3d237c58a20bf1543bc568ab2422411d762dd3d5bf - languageName: node - linkType: hard - "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -7987,15 +7905,6 @@ __metadata: languageName: node linkType: hard -"formdata-polyfill@npm:^4.0.10": - version: 4.0.10 - resolution: "formdata-polyfill@npm:4.0.10" - dependencies: - fetch-blob: ^3.1.2 - checksum: 82a34df292afadd82b43d4a740ce387bc08541e0a534358425193017bf9fb3567875dc5f69564984b1da979979b70703aa73dee715a17b6c229752ae736dd9db - languageName: node - linkType: hard - "formidable@npm:^2.1.2": version: 2.1.2 resolution: "formidable@npm:2.1.2" @@ -8614,13 +8523,6 @@ __metadata: languageName: node linkType: hard -"hyperdyperid@npm:^1.2.0": - version: 1.2.0 - resolution: "hyperdyperid@npm:1.2.0" - checksum: 210029d1c86926f09109f6317d143f8b056fc38e8dd11b0c3e3205fc6c6ff8429fb55b4b9c2bce065462719ed9d34366eced387aaa0035d93eb76b306a8547ef - languageName: node - linkType: hard - "iconv-lite@npm:0.4.24": version: 0.4.24 resolution: "iconv-lite@npm:0.4.24" @@ -8653,13 +8555,6 @@ __metadata: languageName: node linkType: hard -"immediate@npm:~3.0.5": - version: 3.0.6 - resolution: "immediate@npm:3.0.6" - checksum: f9b3486477555997657f70318cc8d3416159f208bec4cca3ff3442fd266bc23f50f0c9bd8547e1371a6b5e82b821ec9a7044a4f7b944798b25aa3cc6d5e63e62 - languageName: node - linkType: hard - "import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" @@ -10087,18 +9982,6 @@ __metadata: languageName: node linkType: hard -"jszip@npm:^3.10.1": - version: 3.10.1 - resolution: "jszip@npm:3.10.1" - dependencies: - lie: ~3.3.0 - pako: ~1.0.2 - readable-stream: ~2.3.6 - setimmediate: ^1.0.5 - checksum: abc77bfbe33e691d4d1ac9c74c8851b5761fba6a6986630864f98d876f3fcc2d36817dfc183779f32c00157b5d53a016796677298272a714ae096dfe6b1c8b60 - languageName: node - linkType: hard - "keygrip@npm:~1.1.0": version: 1.1.0 resolution: "keygrip@npm:1.1.0" @@ -10365,15 +10248,6 @@ __metadata: languageName: node linkType: hard -"lie@npm:~3.3.0": - version: 3.3.0 - resolution: "lie@npm:3.3.0" - dependencies: - immediate: ~3.0.5 - checksum: 33102302cf19766f97919a6a98d481e01393288b17a6aa1f030a3542031df42736edde8dab29ffdbf90bebeffc48c761eb1d064dc77592ca3ba3556f9fe6d2a8 - languageName: node - linkType: hard - "lines-and-columns@npm:^1.1.6": version: 1.2.4 resolution: "lines-and-columns@npm:1.2.4" @@ -10467,13 +10341,6 @@ __metadata: languageName: node linkType: hard -"lodash.capitalize@npm:^4.2.1": - version: 4.2.1 - resolution: "lodash.capitalize@npm:4.2.1" - checksum: d9195f31d48c105206f1099946d8bbc8ab71435bc1c8708296992a31a992bb901baf120fdcadd773098ac96e62a79e6b023ee7d26a2deb0d6c6aada930e6ad0a - languageName: node - linkType: hard - "lodash.chunk@npm:^4.2.0": version: 4.2.0 resolution: "lodash.chunk@npm:4.2.0" @@ -10551,13 +10418,6 @@ __metadata: languageName: node linkType: hard -"lodash.startcase@npm:^4.4.0": - version: 4.4.0 - resolution: "lodash.startcase@npm:4.4.0" - checksum: c03a4a784aca653845fe09d0ef67c902b6e49288dc45f542a4ab345a9c406a6dc194c774423fa313ee7b06283950301c1221dd2a1d8ecb2dac8dfbb9ed5606b5 - languageName: node - linkType: hard - "lodash.times@npm:^4.3.2": version: 4.3.2 resolution: "lodash.times@npm:4.3.2" @@ -10792,18 +10652,6 @@ __metadata: languageName: node linkType: hard -"memfs@npm:^4.6.0": - version: 4.9.2 - resolution: "memfs@npm:4.9.2" - dependencies: - "@jsonjoy.com/json-pack": ^1.0.3 - "@jsonjoy.com/util": ^1.1.2 - sonic-forest: ^1.0.0 - tslib: ^2.0.0 - checksum: 72850691d37b4e67fb78fceced7294e381caf7a614b22b81fa643c03ac6c13270d52e2ac96d8ed95edab715fd0fba2db1bf604a815cbd6d53ecb3f56c038a583 - languageName: node - linkType: hard - "memorystream@npm:^0.3.1": version: 0.3.1 resolution: "memorystream@npm:0.3.1" @@ -11282,24 +11130,6 @@ __metadata: languageName: node linkType: hard -"node-domexception@npm:^1.0.0": - version: 1.0.0 - resolution: "node-domexception@npm:1.0.0" - checksum: ee1d37dd2a4eb26a8a92cd6b64dfc29caec72bff5e1ed9aba80c294f57a31ba4895a60fd48347cf17dd6e766da0ae87d75657dfd1f384ebfa60462c2283f5c7f - languageName: node - linkType: hard - -"node-fetch@npm:^3.3.2": - version: 3.3.2 - resolution: "node-fetch@npm:3.3.2" - dependencies: - data-uri-to-buffer: ^4.0.0 - fetch-blob: ^3.1.4 - formdata-polyfill: ^4.0.10 - checksum: 06a04095a2ddf05b0830a0d5302699704d59bda3102894ea64c7b9d4c865ecdff2d90fd042df7f5bc40337266961cb6183dcc808ea4f3000d024f422b462da92 - languageName: node - linkType: hard - "node-forge@npm:^1.1.0": version: 1.3.1 resolution: "node-forge@npm:1.3.1" @@ -11748,13 +11578,6 @@ __metadata: languageName: node linkType: hard -"pako@npm:~1.0.2": - version: 1.0.11 - resolution: "pako@npm:1.0.11" - checksum: 1be2bfa1f807608c7538afa15d6f25baa523c30ec870a3228a89579e474a4d992f4293859524e46d5d87fd30fa17c5edf34dbef0671251d9749820b488660b16 - languageName: node - linkType: hard - "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -12398,7 +12221,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.3.8, readable-stream@npm:~2.3.6": +"readable-stream@npm:^2.3.8": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -12882,13 +12705,6 @@ __metadata: languageName: node linkType: hard -"setimmediate@npm:^1.0.5": - version: 1.0.5 - resolution: "setimmediate@npm:1.0.5" - checksum: c9a6f2c5b51a2dabdc0247db9c46460152ffc62ee139f3157440bd48e7c59425093f42719ac1d7931f054f153e2d26cf37dfeb8da17a794a58198a2705e527fd - languageName: node - linkType: hard - "setprototypeof@npm:1.1.0": version: 1.1.0 resolution: "setprototypeof@npm:1.1.0" @@ -13089,17 +12905,6 @@ __metadata: languageName: node linkType: hard -"sonic-forest@npm:^1.0.0": - version: 1.0.3 - resolution: "sonic-forest@npm:1.0.3" - dependencies: - tree-dump: ^1.0.0 - peerDependencies: - tslib: 2 - checksum: d328735d527ad9e27b3ed9a1599abf33a1e2df139b3689c6515c3c1fa09f19d0a9ddccdc1a43759fa43462259a962308cb18214bed761c1b7ea75a7611e31b11 - languageName: node - linkType: hard - "source-map-js@npm:^1.2.0": version: 1.2.0 resolution: "source-map-js@npm:1.2.0" @@ -13693,15 +13498,6 @@ __metadata: languageName: node linkType: hard -"thingies@npm:^1.20.0": - version: 1.21.0 - resolution: "thingies@npm:1.21.0" - peerDependencies: - tslib: ^2 - checksum: 283a2785e513dc892822dd0bbadaa79e873a7fc90b84798164717bf7cf837553e0b4518d8027b2307d8f6fc6caab088fa717112cd9196c6222763cc3cc1b7e79 - languageName: node - linkType: hard - "through@npm:2, through@npm:^2.3.8, through@npm:~2.3, through@npm:~2.3.1": version: 2.3.8 resolution: "through@npm:2.3.8" @@ -13748,15 +13544,6 @@ __metadata: languageName: node linkType: hard -"tree-dump@npm:^1.0.0": - version: 1.0.1 - resolution: "tree-dump@npm:1.0.1" - peerDependencies: - tslib: 2 - checksum: 256f2e066ab8743672795822731410d9b9036ef449499f528df1a638ad99af45f345bfbddeaf1cc46b7b9279db3b5f83e1a4cb21bc086ef25ce6add975a3c490 - languageName: node - linkType: hard - "tree-kill@npm:^1.2.2": version: 1.2.2 resolution: "tree-kill@npm:1.2.2" @@ -13954,7 +13741,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.1": +"tslib@npm:^2.0.1, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.1": version: 2.6.2 resolution: "tslib@npm:2.6.2" checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad @@ -14287,15 +14074,6 @@ __metadata: languageName: node linkType: hard -"unzipit@npm:^1.4.3": - version: 1.4.3 - resolution: "unzipit@npm:1.4.3" - dependencies: - uzip-module: ^1.0.2 - checksum: ce29348edab7b5fb5b7b4d43437f48e35812ac8b3cc2d76efd1acfcad6dd1b96b4f96bfd03250a724b87ba99dd531d7727ad24b590acf727dde79f54f5e779ed - languageName: node - linkType: hard - "upath@npm:^2.0.1": version: 2.0.1 resolution: "upath@npm:2.0.1" @@ -14353,13 +14131,6 @@ __metadata: languageName: node linkType: hard -"uzip-module@npm:^1.0.2": - version: 1.0.3 - resolution: "uzip-module@npm:1.0.3" - checksum: fc286c44a04d75055577fae8293d3fee499d1e850f87e88c158b1e3657f4794a3a40ca2d34f73474ff82917176dd5ca9d1c0d1e375a083714e11afabd3afa423 - languageName: node - linkType: hard - "v8-compile-cache-lib@npm:^3.0.1": version: 3.0.1 resolution: "v8-compile-cache-lib@npm:3.0.1" @@ -14512,13 +14283,6 @@ __metadata: languageName: node linkType: hard -"web-streams-polyfill@npm:^3.0.3": - version: 3.3.3 - resolution: "web-streams-polyfill@npm:3.3.3" - checksum: 21ab5ea08a730a2ef8023736afe16713b4f2023ec1c7085c16c8e293ee17ed085dff63a0ad8722da30c99c4ccbd4ccd1b2e79c861829f7ef2963d7de7004c2cb - languageName: node - linkType: hard - "webpack-cli@npm:^5.1.4": version: 5.1.4 resolution: "webpack-cli@npm:5.1.4"