From bf58b523f10bdbbd3cf695c3ef889de1ab129ca8 Mon Sep 17 00:00:00 2001 From: spypsy Date: Thu, 3 Aug 2023 13:19:35 +0300 Subject: [PATCH 1/5] CLI update to use options instead of args --- yarn-project/aztec-cli/README.md | 32 +++--- yarn-project/aztec-cli/src/index.ts | 106 ++++++++++++------- yarn-project/aztec-cli/src/utils.ts | 20 +++- yarn-project/noir-contracts/scripts/types.sh | 19 +++- 4 files changed, 112 insertions(+), 65 deletions(-) diff --git a/yarn-project/aztec-cli/README.md b/yarn-project/aztec-cli/README.md index d6493cf2b2e..64704f40a67 100644 --- a/yarn-project/aztec-cli/README.md +++ b/yarn-project/aztec-cli/README.md @@ -143,11 +143,10 @@ Syntax: aztec-cli deploy [options] ``` -- `contractAbi`: Path to the compiled Noir contract's ABI file in JSON format. -- `constructorArgs` (optional): Contract constructor arguments. - Options: +- `-c, --contract-abi `: Path to the compiled Noir contract's ABI file in JSON format. +- `-a, --args ` (optional): Contract constructor arguments Default: []. - `-u, --rpc-url `: URL of the Aztec RPC. Default: `http://localhost:8080`. - `-k, --public-key `: Public key of the deployer. If not provided, it will check the RPC for existing ones. @@ -156,7 +155,7 @@ This command deploys a compiled Noir contract to Aztec. It requires the path to Example usage: ```shell -aztec-cli deploy path/to/contract.abi.json ...args +aztec-cli deploy -c path/to/contract.abi.json -a ...args ``` ### check-deploy @@ -169,10 +168,9 @@ Syntax: aztec-cli check-deploy [options] ``` -- `contractAddress`: An Aztec address to check if the contract has been deployed to. - Options: +- `-ca, --contract-address
`: An Aztec address to check if the contract has been deployed to. - `-u, --rpc-url `: URL of the Aztec RPC. Default: `http://localhost:8080`. This command checks if a contract is deployed to the specified Aztec address. It verifies if the contract is present at the given address and displays the result. @@ -180,7 +178,7 @@ This command checks if a contract is deployed to the specified Aztec address. It Example usage: ```shell -aztec-cli check-deploy 0x123456789abcdef123456789abcdef12345678 +aztec-cli check-deploy -ca 0x123456789abcdef123456789abcdef12345678 ``` ### get-tx-receipt @@ -278,7 +276,7 @@ Example usage: aztec-cli get-account-public-key 0x123456789abcdef123456789abcdef12345678 ``` -### call-fn +### send Calls a function on an Aztec contract. @@ -288,13 +286,13 @@ Syntax: aztec-cli call-fn [functionArgs...] [options] ``` -- `contractAbi`: The compiled contract's ABI in JSON format. -- `contractAddress`: Address of the contract. - `functionName`: Name of the function to call. -- `functionArgs` (optional): Function arguments. Options: +- `'-a, --args [functionArgs...]` (optional): Function arguments. Default: []. +- `-c, --contract-abi `: The compiled contract's ABI in JSON format. +- `-ca, --contract-address
`: Address of the contract. - `-k, --private-key `: The sender's private key. - `-u, --rpcUrl `: URL of the Aztec RPC. Default: `http://localhost:8080`. @@ -303,7 +301,7 @@ This command calls a function on an Aztec contract. It requires the contract's A Example usage: ```shell -aztec-cli call-fn path/to/contract.abi.json 0x123456789abcdef123456789abcdef12345678 transfer 100 +aztec-cli send transfer -ca 0x123456789abcdef123456789abcdef12345678 -a 100 -c path/to/abi.json ``` ### view-fn @@ -313,16 +311,16 @@ Simulates the execution of a view (read-only) function on a deployed contract, w Syntax: ```shell -aztec-cli view-fn [functionArgs...] [options] +aztec-cli call [functionArgs...] [options] ``` -- `contractAbi`: The compiled contract's ABI in JSON format. -- `contractAddress`: Address of the contract. - `functionName`: Name of the function to view. -- `functionArgs` (optional): Function arguments. Options: +- `'-a, --args [functionArgs...]` (optional): Function arguments. Default: []. +- `-c, --contract-abi `: The compiled contract's ABI in JSON format. +- `-ca, --contract-address
`: Address of the contract. - `-f, --from `: Public key of the transaction viewer. If empty, it will try to find an account in the RPC. - `-u, --rpcUrl `: URL of the Aztec RPC. Default: `http://localhost:8080`. @@ -331,7 +329,7 @@ This command simulates the execution of a view function on a deployed contract w Example usage: ```shell -aztec-cli view-fn path/to/contract.abi.json 0x123456789abcdef123456789abcdef12345678 balanceOf 0xabcdef1234567890abcdef1234567890abcdef12 +aztec-cli call balanceOf -c path/to/contract.abi.json -ca 0x123456789abcdef123456789abcdef12345678 -a balanceOf 0xabcdef1234567890abcdef1234567890abcdef12 ``` ### parse-parameter-struct diff --git a/yarn-project/aztec-cli/src/index.ts b/yarn-project/aztec-cli/src/index.ts index 942da3dde12..ff1e1f8dc0f 100644 --- a/yarn-project/aztec-cli/src/index.ts +++ b/yarn-project/aztec-cli/src/index.ts @@ -20,7 +20,7 @@ import { Command } from 'commander'; import { mnemonicToAccount } from 'viem/accounts'; import { encodeArgs, parseStructString } from './cli_encoder.js'; -import { deployAztecContracts, getContractAbi, getTxSender, prepTx } from './utils.js'; +import { deployAztecContracts, getAbiFunction, getContractAbi, getTxSender, prepTx } from './utils.js'; const accountCreationSalt = Fr.ZERO; @@ -46,8 +46,8 @@ async function main() { program .command('deploy-l1-contracts') .description('Deploys all necessary Ethereum contracts for Aztec.') - .argument( - '[rpcUrl]', + .option( + '-u, --rpc-url ', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST || 'http://localhost:8545', ) @@ -58,9 +58,15 @@ async function main() { 'The mnemonic to use in deployment', 'test test test test test test test test test test test junk', ) - .action(async (rpcUrl: string, options) => { + .action(async options => { const { rollupAddress, registryAddress, inboxAddress, outboxAddress, contractDeploymentEmitterAddress } = - await deployAztecContracts(rpcUrl, options.apiKey ?? '', options.privateKey, options.mnemonic, debugLogger); + await deployAztecContracts( + options.rpcUrl, + options.apiKey ?? '', + options.privateKey, + options.mnemonic, + debugLogger, + ); log('\n'); log(`Rollup Address: ${rollupAddress.toString()}`); log(`Registry Address: ${registryAddress.toString()}`); @@ -105,7 +111,7 @@ async function main() { const wallet = await createAccounts( client, SchnorrSingleKeyAccountContractAbi, - new PrivateKey(privateKey), + privateKey && new PrivateKey(privateKey), accountCreationSalt, 1, ); @@ -118,16 +124,16 @@ async function main() { program .command('deploy') .description('Deploys a compiled Noir contract to Aztec.') - .argument('', "A compiled Noir contract's ABI in JSON format", undefined) - .argument('[constructorArgs...]', 'Contract constructor arguments', []) + .option('-c, --contract-abi ', "A compiled Noir contract's ABI in JSON format", undefined) + .option('-a, --args ', 'Contract constructor arguments', []) .option('-u, --rpc-url ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') .option( '-k, --public-key ', 'Public key of the deployer. If not provided, it will check the RPC for existing ones.', PUBLIC_KEY, ) - .action(async (contractFile: string, args: string[], options: any) => { - const contractAbi = getContractAbi(contractFile, log); + .action(async (options: any) => { + const contractAbi = getContractAbi(options.contractAbi, log); const constructorAbi = contractAbi.functions.find(({ name }) => name === 'constructor'); const client = createAztecRpcClient(options.rpcUrl); @@ -146,7 +152,14 @@ async function main() { const deployer = new ContractDeployer(contractAbi, client); - const tx = deployer.deploy(...encodeArgs(args, constructorAbi!.parameters), publicKey.toBigInts()).send(); + const constructor = getAbiFunction(contractAbi, 'constructor'); + if (constructor.parameters.length !== options.args.length) { + throw Error( + `Invalid number of args passed. Expected ${constructor.parameters.length}; Received: ${options.args.length}`, + ); + } + + const tx = deployer.deploy(...encodeArgs(options.args, constructorAbi!.parameters), publicKey.toBigInts()).send(); await tx.isMined(); const receipt = await tx.getReceipt(); log(`\nAztec Contract deployed at ${receipt.contractAddress?.toString()}\n`); @@ -155,19 +168,19 @@ async function main() { program .command('check-deploy') .description('Checks if a contract is deployed to the specified Aztec address.') - .argument('', 'An Aztec address to check if contract has been deployed to.') - .option('-u, --rpc-url ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') - .action(async (_contractAddress, options) => { + .option('-ca, --contract-address
', 'An Aztec address to check if contract has been deployed to.') + .option('-u, --rpc-url ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') + .action(async options => { const client = createAztecRpcClient(options.rpcUrl); - const address = AztecAddress.fromString(_contractAddress); + const address = AztecAddress.fromString(options.contractAddress); const isDeployed = await client.isContractDeployed(address); log(`\n${isDeployed.toString()}\n`); }); program .command('get-tx-receipt') - .description('Gets the receipt for the specified transaction hash.') .argument('', 'A TX hash to get the receipt for.') + .description('Gets the receipt for the specified transaction hash.') .option('-u, --rpc-url ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') .action(async (_txHash, options) => { const client = createAztecRpcClient(options.rpcUrl); @@ -186,15 +199,15 @@ async function main() { .argument('', 'Aztec address of the contract.') .option('-u, --rpc-url ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') .option('-b, --include-bytecode', "Include the contract's public function bytecode, if any.") - .action(async (_contractAddress, options) => { + .action(async (contractAddress, options) => { const client = createAztecRpcClient(options.rpcUrl); - const address = AztecAddress.fromString(_contractAddress); + const address = AztecAddress.fromString(contractAddress); const contractDataOrInfo = options.includeBytecode ? await client.getContractData(address) : await client.getContractInfo(address); if (!contractDataOrInfo) { - log(`No contract data found at ${_contractAddress}`); + log(`No contract data found at ${contractAddress}`); return; } let contractData: ContractData; @@ -277,22 +290,29 @@ async function main() { program .command('send') .description('Calls a function on an Aztec contract.') - .argument('', "The compiled contract's ABI in JSON format", undefined) - .argument('', 'Address of the contract') .argument('', 'Name of Function to view') - .argument('[functionArgs...]', 'Function arguments', []) + .option('-a, --args [functionArgs...]', 'Function arguments', []) + .option('-c, --contract-abi ', "A compiled Noir contract's ABI in JSON format", undefined) + .option('-ca, --contract-address
', 'Aztec address of the contract.') .option('-k, --private-key ', "The sender's private key.", PRIVATE_KEY) .option('-u, --rpcUrl ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') - .action(async (contractFile, _contractAddress, functionName, _functionArgs, options) => { + .action(async (functionName, options) => { const { contractAddress, functionArgs, contractAbi } = prepTx( - contractFile, - _contractAddress, + options.contractAbi, + options.contractAddress, functionName, - _functionArgs, + options.args, log, ); + const fnAbi = getAbiFunction(contractAbi, functionName); + if (fnAbi.parameters.length !== options.args.length) { + throw Error( + `Invalid number of args passed. Expected ${fnAbi.parameters.length}; Received: ${options.args.length}`, + ); + } + const client = createAztecRpcClient(options.rpcUrl); const wallet = await getAccountWallet( client, @@ -319,20 +339,26 @@ async function main() { .description( 'Simulates the execution of a view (read-only) function on a deployed contract, without modifying state.', ) - .argument('', "The compiled contract's ABI in JSON format", undefined) - .argument('', 'Address of the contract') .argument('', 'Name of Function to view') - .argument('[functionArgs...]', 'Function arguments', []) + .option('-a, --args [functionArgs...]', 'Function arguments', []) + .option('-c, --contract-abi ', "A compiled Noir contract's ABI in JSON format", undefined) + .option('-ca, --contract-address
', 'Aztec address of the contract.') .option('-f, --from ', 'Public key of the TX viewer. If empty, will try to find account in RPC.') .option('-u, --rpcUrl ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') - .action(async (contractFile, _contractAddress, functionName, _functionArgs, options) => { - const { contractAddress, functionArgs } = prepTx( - contractFile, - _contractAddress, + .action(async (functionName, options) => { + const { contractAddress, functionArgs, contractAbi } = prepTx( + options.contractAbi, + options.contractAddress, functionName, - _functionArgs, + options.args, log, ); + const fnAbi = getAbiFunction(contractAbi, functionName); + if (fnAbi.parameters.length !== options.args.length) { + throw Error( + `Invalid number of args passed. Expected ${fnAbi.parameters.length}; Received: ${options.args.length}`, + ); + } const client = createAztecRpcClient(options.rpcUrl); const from = await getTxSender(client, options.from); const result = await client.viewTx(functionName, functionArgs, contractAddress, from); @@ -344,16 +370,16 @@ async function main() { .command('parse-parameter-struct') .description("Helper for parsing an encoded string into a contract's parameter struct.") .argument('', 'The encoded hex string') - .argument('', "The compiled contract's ABI in JSON format") - .argument('', 'The name of the struct parameter to decode into') - .action((encodedString, contractFile, parameterName) => { - const contractAbi = getContractAbi(contractFile, log); + .option('-c, --contract-abi ', "A compiled Noir contract's ABI in JSON format", undefined) + .option('-p, --parameter ', 'The name of the struct parameter to decode into') + .action((encodedString, options) => { + const contractAbi = getContractAbi(options.contractAbi, log); const parameterAbitype = contractAbi.functions .map(({ parameters }) => parameters) .flat() - .find(({ name, type }) => name === parameterName && type.kind === 'struct'); + .find(({ name, type }) => name === options.parameter && type.kind === 'struct'); if (!parameterAbitype) { - log(`No struct parameter found with name ${parameterName}`); + log(`No struct parameter found with name ${options.parameter}`); return; } const data = parseStructString(encodedString, parameterAbitype.type as StructType); diff --git a/yarn-project/aztec-cli/src/utils.ts b/yarn-project/aztec-cli/src/utils.ts index 326544620e5..5a26fc99bda 100644 --- a/yarn-project/aztec-cli/src/utils.ts +++ b/yarn-project/aztec-cli/src/utils.ts @@ -8,6 +8,20 @@ import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts'; import { encodeArgs } from './cli_encoder.js'; +/** + * Helper to get an ABI function or throw error if it doesn't exist. + * @param abi - Contract's ABI in JSON format. + * @param fnName - Function name to be found. + * @returns The function's ABI. + */ +export function getAbiFunction(abi: ContractAbi, fnName: string) { + const fn = abi.functions.find(({ name }) => name === fnName); + if (!fn) { + throw Error(`Function ${fnName} not found in contract ABI.`); + } + return fn; +} + /** * Function to execute the 'deployRollupContracts' command. * @param rpcUrl - The RPC URL of the ethereum node. @@ -92,11 +106,7 @@ export function prepTx( throw new Error(`Unable to parse contract address ${_contractAddress}.`); } const contractAbi = getContractAbi(contractFile, log); - const functionAbi = contractAbi.functions.find(({ name }) => name === functionName); - if (!functionAbi) { - throw new Error(`Function ${functionName} not found on contract ABI.`); - } - + const functionAbi = getAbiFunction(contractAbi, functionName); const functionArgs = encodeArgs(_functionArgs, functionAbi.parameters); return { contractAddress, functionArgs, contractAbi }; diff --git a/yarn-project/noir-contracts/scripts/types.sh b/yarn-project/noir-contracts/scripts/types.sh index 87bbc04b115..7f0b6fa1dd5 100755 --- a/yarn-project/noir-contracts/scripts/types.sh +++ b/yarn-project/noir-contracts/scripts/types.sh @@ -22,14 +22,27 @@ ROOT=$(pwd) write_import() { CONTRACT_NAME=$1 - NAME=`echo $CONTRACT_NAME | sed -r 's/(^|_)(.)/\U\2/g'` + + if [ "$(uname)" = "Darwin" ]; then + # sed \U doesn't work on mac + NAME=$(echo $CONTRACT_NAME | perl -pe 's/(^|_)(\w)/\U$2/g') + else + NAME=`echo $CONTRACT_NAME | sed -r 's/(^|_)(.)/\U\2/g'` + fi + echo "import ${NAME}Json from './${CONTRACT_NAME}_contract.json' assert { type: 'json' };" >> "$artifacts_dir/index.ts"; } write_export() { CONTRACT_NAME=$1 - NAME=`echo $CONTRACT_NAME | sed -r 's/(^|_)(.)/\U\2/g'` - + if [ "$(uname)" = "Darwin" ]; then + # sed \U doesn't work on mac + NAME=$(echo $CONTRACT_NAME | perl -pe 's/(^|_)(\w)/\U$2/g') + else + NAME=`echo $CONTRACT_NAME | sed -r 's/(^|_)(.)/\U\2/g'` + fi + + # artifacts echo "export const ${NAME}ContractAbi = ${NAME}Json as ContractAbi;" >> "$artifacts_dir/index.ts"; echo "Written typescript for $NAME" From f1a2204c5a52f4e56b32b8a37645456656ece920 Mon Sep 17 00:00:00 2001 From: spypsy Date: Thu, 3 Aug 2023 14:48:15 +0300 Subject: [PATCH 2/5] register-public-key --- yarn-project/aztec-cli/README.md | 25 ++++++++++++++++++++++++- yarn-project/aztec-cli/src/index.ts | 18 ++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/yarn-project/aztec-cli/README.md b/yarn-project/aztec-cli/README.md index 64704f40a67..f02beac88f6 100644 --- a/yarn-project/aztec-cli/README.md +++ b/yarn-project/aztec-cli/README.md @@ -230,9 +230,32 @@ Example usage: aztec-cli get-contract-data 0x123456789abcdef123456789abcdef12345678 ``` +### register-public-key + +Register an account's public key to the RPC server + +Syntax: + +```shell +aztec-cli register-public-key [options] +``` + +Options: + +- `-a, --address `: The account's Aztec address. +- `-p, --public-key `: 'The account public key.' +- `-pa, --partial-address `: URL of the Aztec RPC. Default: `http://localhost:8080`. + +Example usage: + +```shell +aztec-cli register-public-key -p 0x20d9d93c4a9eb2b4bdb70ead07d28d1edb74bfd78443a8c36b098b024cd26f0e0647f5dbe3619453f42eb788c2beed0294c84676425047aadac23294605c4af9 -a 0x111fdc0f6bf831ca59f05863199762d643b782699d7ce6feaae40a923baf60af -pa 0x72bf7c9537875b0af267b4a8c497927e251f5988af6e30527feb16299042ed +``` + ### get-accounts -Gets all the Aztec accounts. +Gets all the Aztec accounts stored in an Aztec RPC. Syntax: diff --git a/yarn-project/aztec-cli/src/index.ts b/yarn-project/aztec-cli/src/index.ts index ff1e1f8dc0f..9c036ee7846 100644 --- a/yarn-project/aztec-cli/src/index.ts +++ b/yarn-project/aztec-cli/src/index.ts @@ -251,8 +251,26 @@ async function main() { } }); + program + .command('register-public-key') + .description("Register an account's public key to the RPC server") + .option('-a, --address ', "The account's Aztec address.") + .option('-p, --public-key ', 'The account public key.') + .option('-pa, --partial-address ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') + .action(async options => { + const client = createAztecRpcClient(options.rpcUrl); + const address = AztecAddress.fromString(options.address); + const publicKey = Point.fromString(options.publicKey); + const partialAddress = Fr.fromString(options.partialAddress); + + await client.addPublicKeyAndPartialAddress(address, publicKey, partialAddress); + log(`\nRegistered details for Address: ${options.address}\n`); + }); + program .command('get-accounts') + .description('Gets all the Aztec accounts stored in the Aztec RPC.') .option('-u, --rpc-url ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') .action(async (options: any) => { const client = createAztecRpcClient(options.rpcUrl); From 40fbd2b367306583035338085f98a7605768a302 Mon Sep 17 00:00:00 2001 From: spypsy Date: Thu, 3 Aug 2023 17:29:45 +0300 Subject: [PATCH 3/5] WIP example contracts in aztec-cli --- yarn-project/aztec-cli/src/index.ts | 18 +++++++++++++++++- yarn-project/aztec-cli/src/utils.ts | 8 +++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/yarn-project/aztec-cli/src/index.ts b/yarn-project/aztec-cli/src/index.ts index 9c036ee7846..86f854b77d7 100644 --- a/yarn-project/aztec-cli/src/index.ts +++ b/yarn-project/aztec-cli/src/index.ts @@ -10,7 +10,7 @@ import { generatePublicKey, getAccountWallet, } from '@aztec/aztec.js'; -import { StructType } from '@aztec/foundation/abi'; +import { ContractAbi, StructType } from '@aztec/foundation/abi'; import { JsonStringify } from '@aztec/foundation/json-rpc'; import { createConsoleLogger, createDebugLogger } from '@aztec/foundation/log'; import { SchnorrSingleKeyAccountContractAbi } from '@aztec/noir-contracts/artifacts'; @@ -121,6 +121,22 @@ async function main() { accounts.map((acc, i) => log(`\nAddress: ${acc.toString()}\nPublic Key: ${pubKeys[i].toString()}\n`)); }); + program + .command('deploy-example') + .description('Deploys an compiled Noir contract to Aztec from @aztec/noir-contracts.') + .argument('', 'Name of the contract to be deployed', 'zk_token_contract') + .option('-a, --args ', 'Contract constructor arguments', []) + .option('-u, --rpc-url ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') + .option( + '-k, --public-key ', + 'Public key of the deployer. If not provided, it will check the RPC for existing ones.', + PUBLIC_KEY, + ) + .action(async (contractName, options) => { + const artifacts = await import('@aztec/noir-contracts/artifacts'); + const contractAbi = artifacts[contractName] as ContractAbi; + }); + program .command('deploy') .description('Deploys a compiled Noir contract to Aztec.') diff --git a/yarn-project/aztec-cli/src/utils.ts b/yarn-project/aztec-cli/src/utils.ts index 5a26fc99bda..91cab8a6577 100644 --- a/yarn-project/aztec-cli/src/utils.ts +++ b/yarn-project/aztec-cli/src/utils.ts @@ -1,4 +1,4 @@ -import { AztecAddress, AztecRPC } from '@aztec/aztec.js'; +import { AztecAddress, AztecRPC, Contract } from '@aztec/aztec.js'; import { createEthereumChain, deployL1Contracts } from '@aztec/ethereum'; import { ContractAbi } from '@aztec/foundation/abi'; import { DebugLogger, LogFn } from '@aztec/foundation/log'; @@ -58,6 +58,12 @@ export function getContractAbi(fileDir: string, log: LogFn) { return contractAbi; } +async function getExampleContractAbi(contractName: string): Promise { + const artifacts = await import('@aztec/noir-contracts/artifacts'); + const contractAbi = artifacts[contractName] as Contract; + return contractAbi; +} + /** * Utility to select a TX sender either from user input * or from the first account that is found in an Aztec RPC instance. From 7d44401f10e77dcb8525252b52d9c139b0a85e6d Mon Sep 17 00:00:00 2001 From: spypsy Date: Fri, 4 Aug 2023 10:47:34 +0300 Subject: [PATCH 4/5] enable usage of @aztec/noir-contracts in CLI --- build_manifest.json | 47 +++++++++++++++++++------- yarn-project/aztec-cli/README.md | 12 +++++-- yarn-project/aztec-cli/src/index.ts | 52 ++++++++++++++--------------- yarn-project/aztec-cli/src/utils.ts | 36 ++++++++++++++------ 4 files changed, 95 insertions(+), 52 deletions(-) diff --git a/build_manifest.json b/build_manifest.json index 7e5016900dc..f4cf33f4647 100644 --- a/build_manifest.json +++ b/build_manifest.json @@ -2,54 +2,77 @@ "barretenberg-x86_64-linux-clang": { "buildDir": "circuits/cpp/barretenberg/cpp", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang", - "rebuildPatterns": ["^circuits/cpp/barretenberg/cpp/"], + "rebuildPatterns": [ + "^circuits/cpp/barretenberg/cpp/" + ], "dependencies": [] }, "barretenberg-x86_64-linux-clang-assert": { "buildDir": "circuits/cpp/barretenberg/cpp", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang-assert", - "rebuildPatterns": ["^circuits/cpp/barretenberg/cpp/"], + "rebuildPatterns": [ + "^circuits/cpp/barretenberg/cpp/" + ], "dependencies": [] }, "barretenberg-x86_64-linux-clang-fuzzing": { "buildDir": "circuits/cpp/barretenberg/cpp", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang-fuzzing", - "rebuildPatterns": ["^circuits/cpp/barretenberg/cpp/"], + "rebuildPatterns": [ + "^circuits/cpp/barretenberg/cpp/" + ], "dependencies": [] }, "barretenberg-x86_64-linux-gcc": { "buildDir": "circuits/cpp/barretenberg/cpp", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-gcc", - "rebuildPatterns": ["^circuits/cpp/barretenberg/cpp/"], + "rebuildPatterns": [ + "^circuits/cpp/barretenberg/cpp/" + ], "dependencies": [] }, "barretenberg-wasm-linux-clang": { "buildDir": "circuits/cpp/barretenberg/cpp", "dockerfile": "dockerfiles/Dockerfile.wasm-linux-clang", - "rebuildPatterns": ["^circuits/cpp/barretenberg/cpp/"], + "rebuildPatterns": [ + "^circuits/cpp/barretenberg/cpp/" + ], "dependencies": [] }, "barretenberg-circuits-x86_64-linux-clang-builder-runner": { "buildDir": "circuits/cpp/barretenberg/cpp", "dockerfile": "dockerfiles/Dockerfile.circuits-x86_64-linux-clang-builder-runner", - "rebuildPatterns": ["^circuits/cpp/barretenberg/cpp/"], + "rebuildPatterns": [ + "^circuits/cpp/barretenberg/cpp/" + ], "dependencies": [] }, "barretenberg-circuits-wasm-linux-clang-builder-runner": { "buildDir": "circuits/cpp/barretenberg/cpp", "dockerfile": "dockerfiles/Dockerfile.circuits-wasm-linux-clang-builder-runner", - "rebuildPatterns": ["^circuits/cpp/barretenberg/cpp/"], + "rebuildPatterns": [ + "^circuits/cpp/barretenberg/cpp/" + ], "dependencies": [] }, "bb.js": { "buildDir": "circuits/cpp/barretenberg/ts", - "rebuildPatterns": ["^circuits/cpp/barretenberg/ts/"], - "dependencies": ["barretenberg-wasm-linux-clang"] + "rebuildPatterns": [ + "^circuits/cpp/barretenberg/ts/" + ], + "dependencies": [ + "barretenberg-wasm-linux-clang" + ] }, "barretenberg-acir-tests": { "buildDir": "circuits/cpp/barretenberg/acir_tests", - "rebuildPatterns": ["^circuits/cpp/barretenberg/acir_tests/"], - "dependencies": ["bb.js", "barretenberg-x86_64-linux-clang-assert"] + "rebuildPatterns": [ + "^circuits/cpp/barretenberg/acir_tests/" + ], + "dependencies": [ + "bb.js", + "barretenberg-x86_64-linux-clang-assert" + ] }, "circuits-wasm-linux-clang": { "buildDir": "circuits/cpp", @@ -445,4 +468,4 @@ "types" ] } -} +} \ No newline at end of file diff --git a/yarn-project/aztec-cli/README.md b/yarn-project/aztec-cli/README.md index f02beac88f6..b7462636fc4 100644 --- a/yarn-project/aztec-cli/README.md +++ b/yarn-project/aztec-cli/README.md @@ -145,7 +145,7 @@ aztec-cli deploy [options] Options: -- `-c, --contract-abi `: Path to the compiled Noir contract's ABI file in JSON format. +- `-c, --contract-abi `: Path to the compiled Noir contract's ABI file in JSON format. You can also use one of Aztec's example contracts found in (@aztec/noir-contracts)[https://www.npmjs.com/package/@aztec/noir-contracts], e.g. ZkTokenContractAbi. - `-a, --args ` (optional): Contract constructor arguments Default: []. - `-u, --rpc-url `: URL of the Aztec RPC. Default: `http://localhost:8080`. - `-k, --public-key `: Public key of the deployer. If not provided, it will check the RPC for existing ones. @@ -158,6 +158,12 @@ Example usage: aztec-cli deploy -c path/to/contract.abi.json -a ...args ``` +With an Aztec example contract: + +```shell +aztec-cli deploy -c ZkTokenContractAbi -a 333 0x134567890abcdef +``` + ### check-deploy Checks if a contract is deployed to the specified Aztec address. @@ -314,7 +320,7 @@ aztec-cli call-fn [functionArgs.. Options: - `'-a, --args [functionArgs...]` (optional): Function arguments. Default: []. -- `-c, --contract-abi `: The compiled contract's ABI in JSON format. +- `-c, --contract-abi `: The compiled contract's ABI in JSON format. You can also use one of Aztec's example contracts found in (@aztec/noir-contracts)[https://www.npmjs.com/package/@aztec/noir-contracts], e.g. ZkTokenContractAbi. - `-ca, --contract-address
`: Address of the contract. - `-k, --private-key `: The sender's private key. - `-u, --rpcUrl `: URL of the Aztec RPC. Default: `http://localhost:8080`. @@ -342,7 +348,7 @@ aztec-cli call [functionArgs...] Options: - `'-a, --args [functionArgs...]` (optional): Function arguments. Default: []. -- `-c, --contract-abi `: The compiled contract's ABI in JSON format. +- `-c, --contract-abi `: The compiled contract's ABI in JSON format. You can also use one of Aztec's example contracts found in (@aztec/noir-contracts)[https://www.npmjs.com/package/@aztec/noir-contracts], e.g. ZkTokenContractAbi. - `-ca, --contract-address
`: Address of the contract. - `-f, --from `: Public key of the transaction viewer. If empty, it will try to find an account in the RPC. - `-u, --rpcUrl `: URL of the Aztec RPC. Default: `http://localhost:8080`. diff --git a/yarn-project/aztec-cli/src/index.ts b/yarn-project/aztec-cli/src/index.ts index 86f854b77d7..46dc1391454 100644 --- a/yarn-project/aztec-cli/src/index.ts +++ b/yarn-project/aztec-cli/src/index.ts @@ -10,7 +10,7 @@ import { generatePublicKey, getAccountWallet, } from '@aztec/aztec.js'; -import { ContractAbi, StructType } from '@aztec/foundation/abi'; +import { StructType } from '@aztec/foundation/abi'; import { JsonStringify } from '@aztec/foundation/json-rpc'; import { createConsoleLogger, createDebugLogger } from '@aztec/foundation/log'; import { SchnorrSingleKeyAccountContractAbi } from '@aztec/noir-contracts/artifacts'; @@ -121,26 +121,14 @@ async function main() { accounts.map((acc, i) => log(`\nAddress: ${acc.toString()}\nPublic Key: ${pubKeys[i].toString()}\n`)); }); - program - .command('deploy-example') - .description('Deploys an compiled Noir contract to Aztec from @aztec/noir-contracts.') - .argument('', 'Name of the contract to be deployed', 'zk_token_contract') - .option('-a, --args ', 'Contract constructor arguments', []) - .option('-u, --rpc-url ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') - .option( - '-k, --public-key ', - 'Public key of the deployer. If not provided, it will check the RPC for existing ones.', - PUBLIC_KEY, - ) - .action(async (contractName, options) => { - const artifacts = await import('@aztec/noir-contracts/artifacts'); - const contractAbi = artifacts[contractName] as ContractAbi; - }); - program .command('deploy') .description('Deploys a compiled Noir contract to Aztec.') - .option('-c, --contract-abi ', "A compiled Noir contract's ABI in JSON format", undefined) + .option( + '-c, --contract-abi ', + "A compiled Noir contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts", + undefined, + ) .option('-a, --args ', 'Contract constructor arguments', []) .option('-u, --rpc-url ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') .option( @@ -149,7 +137,7 @@ async function main() { PUBLIC_KEY, ) .action(async (options: any) => { - const contractAbi = getContractAbi(options.contractAbi, log); + const contractAbi = await getContractAbi(options.contractAbi, log); const constructorAbi = contractAbi.functions.find(({ name }) => name === 'constructor'); const client = createAztecRpcClient(options.rpcUrl); @@ -326,13 +314,17 @@ async function main() { .description('Calls a function on an Aztec contract.') .argument('', 'Name of Function to view') .option('-a, --args [functionArgs...]', 'Function arguments', []) - .option('-c, --contract-abi ', "A compiled Noir contract's ABI in JSON format", undefined) + .option( + '-c, --contract-abi ', + "A compiled Noir contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts", + undefined, + ) .option('-ca, --contract-address
', 'Aztec address of the contract.') .option('-k, --private-key ', "The sender's private key.", PRIVATE_KEY) .option('-u, --rpcUrl ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') .action(async (functionName, options) => { - const { contractAddress, functionArgs, contractAbi } = prepTx( + const { contractAddress, functionArgs, contractAbi } = await prepTx( options.contractAbi, options.contractAddress, functionName, @@ -375,12 +367,16 @@ async function main() { ) .argument('', 'Name of Function to view') .option('-a, --args [functionArgs...]', 'Function arguments', []) - .option('-c, --contract-abi ', "A compiled Noir contract's ABI in JSON format", undefined) + .option( + '-c, --contract-abi ', + "A compiled Noir contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts", + undefined, + ) .option('-ca, --contract-address
', 'Aztec address of the contract.') .option('-f, --from ', 'Public key of the TX viewer. If empty, will try to find account in RPC.') .option('-u, --rpcUrl ', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080') .action(async (functionName, options) => { - const { contractAddress, functionArgs, contractAbi } = prepTx( + const { contractAddress, functionArgs, contractAbi } = await prepTx( options.contractAbi, options.contractAddress, functionName, @@ -404,10 +400,14 @@ async function main() { .command('parse-parameter-struct') .description("Helper for parsing an encoded string into a contract's parameter struct.") .argument('', 'The encoded hex string') - .option('-c, --contract-abi ', "A compiled Noir contract's ABI in JSON format", undefined) + .option( + '-c, --contract-abi ', + "A compiled Noir contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts", + undefined, + ) .option('-p, --parameter ', 'The name of the struct parameter to decode into') - .action((encodedString, options) => { - const contractAbi = getContractAbi(options.contractAbi, log); + .action(async (encodedString, options) => { + const contractAbi = await getContractAbi(options.contractAbi, log); const parameterAbitype = contractAbi.functions .map(({ parameters }) => parameters) .flat() diff --git a/yarn-project/aztec-cli/src/utils.ts b/yarn-project/aztec-cli/src/utils.ts index 91cab8a6577..d421f67a4e4 100644 --- a/yarn-project/aztec-cli/src/utils.ts +++ b/yarn-project/aztec-cli/src/utils.ts @@ -1,4 +1,4 @@ -import { AztecAddress, AztecRPC, Contract } from '@aztec/aztec.js'; +import { AztecAddress, AztecRPC } from '@aztec/aztec.js'; import { createEthereumChain, deployL1Contracts } from '@aztec/ethereum'; import { ContractAbi } from '@aztec/foundation/abi'; import { DebugLogger, LogFn } from '@aztec/foundation/log'; @@ -8,6 +8,13 @@ import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts'; import { encodeArgs } from './cli_encoder.js'; +/** + * Helper type to dynamically import contarcts. + */ +interface ArtifactsType { + [key: string]: ContractAbi; +} + /** * Helper to get an ABI function or throw error if it doesn't exist. * @param abi - Contract's ABI in JSON format. @@ -46,8 +53,21 @@ export async function deployAztecContracts( * @param fileDir - The directory of the compiled contract ABI. * @returns The parsed ContractABI. */ -export function getContractAbi(fileDir: string, log: LogFn) { - const contents = fs.readFileSync(fileDir, 'utf8'); +export async function getContractAbi(fileDir: string, log: LogFn) { + // first check if it's a noir-contracts example + let contents: string; + const artifacts: ArtifactsType = await import('@aztec/noir-contracts/artifacts'); + if (artifacts[fileDir]) { + return artifacts[fileDir] as ContractAbi; + } + + try { + contents = fs.readFileSync(fileDir, 'utf8'); + } catch { + throw Error(`Contract ${fileDir} not found`); + } + + // if not found, try reading as path directly let contractAbi: ContractAbi; try { contractAbi = JSON.parse(contents) as ContractAbi; @@ -58,12 +78,6 @@ export function getContractAbi(fileDir: string, log: LogFn) { return contractAbi; } -async function getExampleContractAbi(contractName: string): Promise { - const artifacts = await import('@aztec/noir-contracts/artifacts'); - const contractAbi = artifacts[contractName] as Contract; - return contractAbi; -} - /** * Utility to select a TX sender either from user input * or from the first account that is found in an Aztec RPC instance. @@ -98,7 +112,7 @@ export async function getTxSender(client: AztecRPC, _from?: string) { * @param log - Logger instance that will output to the CLI * @returns Formatted contract address, function arguments and caller's aztec address. */ -export function prepTx( +export async function prepTx( contractFile: string, _contractAddress: string, functionName: string, @@ -111,7 +125,7 @@ export function prepTx( } catch { throw new Error(`Unable to parse contract address ${_contractAddress}.`); } - const contractAbi = getContractAbi(contractFile, log); + const contractAbi = await getContractAbi(contractFile, log); const functionAbi = getAbiFunction(contractAbi, functionName); const functionArgs = encodeArgs(_functionArgs, functionAbi.parameters); From 09bf18c7cdd4bc372f3c3edd19c66fedc1009fc2 Mon Sep 17 00:00:00 2001 From: spypsy Date: Fri, 4 Aug 2023 10:31:24 +0000 Subject: [PATCH 5/5] PR comments --- yarn-project/aztec-cli/README.md | 15 ++++++++++----- yarn-project/aztec-cli/src/index.ts | 18 +++++++++++++++++- yarn-project/aztec-cli/src/utils.ts | 11 ++++++++++- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/yarn-project/aztec-cli/README.md b/yarn-project/aztec-cli/README.md index b7462636fc4..61c205508bf 100644 --- a/yarn-project/aztec-cli/README.md +++ b/yarn-project/aztec-cli/README.md @@ -145,7 +145,7 @@ aztec-cli deploy [options] Options: -- `-c, --contract-abi `: Path to the compiled Noir contract's ABI file in JSON format. You can also use one of Aztec's example contracts found in (@aztec/noir-contracts)[https://www.npmjs.com/package/@aztec/noir-contracts], e.g. ZkTokenContractAbi. +- `-c, --contract-abi `: Path to the compiled Noir contract's ABI file in JSON format. You can also use one of Aztec's example contracts found in [@aztec/noir-contracts](https://www.npmjs.com/package/@aztec/noir-contracts), e.g. ZkTokenContractAbi. You can get a full ist of the available contracts with `aztec-cli example-contracts` - `-a, --args ` (optional): Contract constructor arguments Default: []. - `-u, --rpc-url `: URL of the Aztec RPC. Default: `http://localhost:8080`. - `-k, --public-key `: Public key of the deployer. If not provided, it will check the RPC for existing ones. @@ -238,7 +238,8 @@ aztec-cli get-contract-data 0x123456789abcdef123456789abcdef12345678 ### register-public-key -Register an account's public key to the RPC server +Register an account's public key to the RPC server. +To read about how keys are generated and used, head to our docs [here](https://github.com/AztecProtocol/aztec-packages/blob/master/docs/docs/aztec/developer/wallet-providers/keys.md#addresses-partial-addresses-and-public-keys). Syntax: @@ -415,7 +416,7 @@ Gets the current Aztec L2 block number. Syntax: ```shell -aztec-cli block-num [options] +aztec-cli block-number ``` Options: @@ -424,10 +425,14 @@ Options: This command retrieves and displays the current Aztec L2 block number. -Example usage: +### example-contracts + +Lists the contracts available in [@aztec/noir-contracts](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts) + +Syntax: ```shell -aztec-cli block-num +aztec-cli example-contracts ``` ## Conclusion diff --git a/yarn-project/aztec-cli/src/index.ts b/yarn-project/aztec-cli/src/index.ts index 46dc1391454..1f02f8b68a9 100644 --- a/yarn-project/aztec-cli/src/index.ts +++ b/yarn-project/aztec-cli/src/index.ts @@ -20,7 +20,14 @@ import { Command } from 'commander'; import { mnemonicToAccount } from 'viem/accounts'; import { encodeArgs, parseStructString } from './cli_encoder.js'; -import { deployAztecContracts, getAbiFunction, getContractAbi, getTxSender, prepTx } from './utils.js'; +import { + deployAztecContracts, + getAbiFunction, + getContractAbi, + getExampleContractArtifacts, + getTxSender, + prepTx, +} from './utils.js'; const accountCreationSalt = Fr.ZERO; @@ -430,6 +437,15 @@ async function main() { log(`${num}\n`); }); + program + .command('example-contracts') + .description('Lists the example contracts available to deploy from @aztec/noir-contracts') + .action(async () => { + const abisList = await getExampleContractArtifacts(); + const names = Object.keys(abisList); + names.forEach(name => log(name)); + }); + await program.parseAsync(process.argv); } diff --git a/yarn-project/aztec-cli/src/utils.ts b/yarn-project/aztec-cli/src/utils.ts index d421f67a4e4..3c16ec7d437 100644 --- a/yarn-project/aztec-cli/src/utils.ts +++ b/yarn-project/aztec-cli/src/utils.ts @@ -48,6 +48,15 @@ export async function deployAztecContracts( return await deployL1Contracts(chain.rpcUrl, account, chain.chainInfo, debugLogger); } +/** + * Gets all contracts available in \@aztec/noir-contracts. + * @returns The contract ABIs. + */ +export async function getExampleContractArtifacts() { + const artifacts: ArtifactsType = await import('@aztec/noir-contracts/artifacts'); + return artifacts; +} + /** * Reads a file and converts it to an Aztec Contract ABI. * @param fileDir - The directory of the compiled contract ABI. @@ -56,7 +65,7 @@ export async function deployAztecContracts( export async function getContractAbi(fileDir: string, log: LogFn) { // first check if it's a noir-contracts example let contents: string; - const artifacts: ArtifactsType = await import('@aztec/noir-contracts/artifacts'); + const artifacts = await getExampleContractArtifacts(); if (artifacts[fileDir]) { return artifacts[fileDir] as ContractAbi; }