@aztec/cli 0.1.0-alpha29 → 0.1.0-alpha31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@aztec/cli",
3
- "version": "0.1.0-alpha29",
3
+ "version": "0.1.0-alpha31",
4
4
  "main": "./dest/index.js",
5
5
  "type": "module",
6
6
  "dependencies": {
7
- "@aztec/aztec.js": "0.1.0-alpha29",
8
- "@aztec/ethereum": "0.1.0-alpha29",
9
- "@aztec/foundation": "0.1.0-alpha29",
10
- "@aztec/noir-contracts": "0.1.0-alpha29",
11
- "@aztec/types": "0.1.0-alpha29",
7
+ "@aztec/aztec.js": "0.1.0-alpha31",
8
+ "@aztec/ethereum": "0.1.0-alpha31",
9
+ "@aztec/foundation": "0.1.0-alpha31",
10
+ "@aztec/noir-contracts": "0.1.0-alpha31",
11
+ "@aztec/types": "0.1.0-alpha31",
12
12
  "commander": "^9.0.0",
13
13
  "tslib": "^2.4.0",
14
14
  "viem": "^1.2.5"
package/src/index.ts CHANGED
@@ -20,7 +20,14 @@ import { Command } from 'commander';
20
20
  import { mnemonicToAccount } from 'viem/accounts';
21
21
 
22
22
  import { encodeArgs, parseStructString } from './cli_encoder.js';
23
- import { deployAztecContracts, getContractAbi, getTxSender, prepTx } from './utils.js';
23
+ import {
24
+ deployAztecContracts,
25
+ getAbiFunction,
26
+ getContractAbi,
27
+ getExampleContractArtifacts,
28
+ getTxSender,
29
+ prepTx,
30
+ } from './utils.js';
24
31
 
25
32
  const accountCreationSalt = Fr.ZERO;
26
33
 
@@ -46,8 +53,8 @@ async function main() {
46
53
  program
47
54
  .command('deploy-l1-contracts')
48
55
  .description('Deploys all necessary Ethereum contracts for Aztec.')
49
- .argument(
50
- '[rpcUrl]',
56
+ .option(
57
+ '-u, --rpc-url <string>',
51
58
  'Url of the ethereum host. Chain identifiers localhost and testnet can be used',
52
59
  ETHEREUM_HOST || 'http://localhost:8545',
53
60
  )
@@ -58,9 +65,15 @@ async function main() {
58
65
  'The mnemonic to use in deployment',
59
66
  'test test test test test test test test test test test junk',
60
67
  )
61
- .action(async (rpcUrl: string, options) => {
68
+ .action(async options => {
62
69
  const { rollupAddress, registryAddress, inboxAddress, outboxAddress, contractDeploymentEmitterAddress } =
63
- await deployAztecContracts(rpcUrl, options.apiKey ?? '', options.privateKey, options.mnemonic, debugLogger);
70
+ await deployAztecContracts(
71
+ options.rpcUrl,
72
+ options.apiKey ?? '',
73
+ options.privateKey,
74
+ options.mnemonic,
75
+ debugLogger,
76
+ );
64
77
  log('\n');
65
78
  log(`Rollup Address: ${rollupAddress.toString()}`);
66
79
  log(`Registry Address: ${registryAddress.toString()}`);
@@ -105,7 +118,7 @@ async function main() {
105
118
  const wallet = await createAccounts(
106
119
  client,
107
120
  SchnorrSingleKeyAccountContractAbi,
108
- new PrivateKey(privateKey),
121
+ privateKey && new PrivateKey(privateKey),
109
122
  accountCreationSalt,
110
123
  1,
111
124
  );
@@ -118,16 +131,20 @@ async function main() {
118
131
  program
119
132
  .command('deploy')
120
133
  .description('Deploys a compiled Noir contract to Aztec.')
121
- .argument('<contractAbi>', "A compiled Noir contract's ABI in JSON format", undefined)
122
- .argument('[constructorArgs...]', 'Contract constructor arguments', [])
134
+ .option(
135
+ '-c, --contract-abi <file>',
136
+ "A compiled Noir contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts",
137
+ undefined,
138
+ )
139
+ .option('-a, --args <constructorArgs...>', 'Contract constructor arguments', [])
123
140
  .option('-u, --rpc-url <string>', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080')
124
141
  .option(
125
142
  '-k, --public-key <string>',
126
143
  'Public key of the deployer. If not provided, it will check the RPC for existing ones.',
127
144
  PUBLIC_KEY,
128
145
  )
129
- .action(async (contractFile: string, args: string[], options: any) => {
130
- const contractAbi = getContractAbi(contractFile, log);
146
+ .action(async (options: any) => {
147
+ const contractAbi = await getContractAbi(options.contractAbi, log);
131
148
  const constructorAbi = contractAbi.functions.find(({ name }) => name === 'constructor');
132
149
 
133
150
  const client = createAztecRpcClient(options.rpcUrl);
@@ -146,7 +163,14 @@ async function main() {
146
163
 
147
164
  const deployer = new ContractDeployer(contractAbi, client);
148
165
 
149
- const tx = deployer.deploy(...encodeArgs(args, constructorAbi!.parameters), publicKey.toBigInts()).send();
166
+ const constructor = getAbiFunction(contractAbi, 'constructor');
167
+ if (constructor.parameters.length !== options.args.length) {
168
+ throw Error(
169
+ `Invalid number of args passed. Expected ${constructor.parameters.length}; Received: ${options.args.length}`,
170
+ );
171
+ }
172
+
173
+ const tx = deployer.deploy(...encodeArgs(options.args, constructorAbi!.parameters), publicKey.toBigInts()).send();
150
174
  await tx.isMined();
151
175
  const receipt = await tx.getReceipt();
152
176
  log(`\nAztec Contract deployed at ${receipt.contractAddress?.toString()}\n`);
@@ -155,19 +179,19 @@ async function main() {
155
179
  program
156
180
  .command('check-deploy')
157
181
  .description('Checks if a contract is deployed to the specified Aztec address.')
158
- .argument('<contractAddress>', 'An Aztec address to check if contract has been deployed to.')
159
- .option('-u, --rpc-url <string>', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080')
160
- .action(async (_contractAddress, options) => {
182
+ .option('-ca, --contract-address <address>', 'An Aztec address to check if contract has been deployed to.')
183
+ .option('-u, --rpc-url <url>', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080')
184
+ .action(async options => {
161
185
  const client = createAztecRpcClient(options.rpcUrl);
162
- const address = AztecAddress.fromString(_contractAddress);
186
+ const address = AztecAddress.fromString(options.contractAddress);
163
187
  const isDeployed = await client.isContractDeployed(address);
164
188
  log(`\n${isDeployed.toString()}\n`);
165
189
  });
166
190
 
167
191
  program
168
192
  .command('get-tx-receipt')
169
- .description('Gets the receipt for the specified transaction hash.')
170
193
  .argument('<txHash>', 'A TX hash to get the receipt for.')
194
+ .description('Gets the receipt for the specified transaction hash.')
171
195
  .option('-u, --rpc-url <string>', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080')
172
196
  .action(async (_txHash, options) => {
173
197
  const client = createAztecRpcClient(options.rpcUrl);
@@ -186,15 +210,15 @@ async function main() {
186
210
  .argument('<contractAddress>', 'Aztec address of the contract.')
187
211
  .option('-u, --rpc-url <string>', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080')
188
212
  .option('-b, --include-bytecode', "Include the contract's public function bytecode, if any.")
189
- .action(async (_contractAddress, options) => {
213
+ .action(async (contractAddress, options) => {
190
214
  const client = createAztecRpcClient(options.rpcUrl);
191
- const address = AztecAddress.fromString(_contractAddress);
215
+ const address = AztecAddress.fromString(contractAddress);
192
216
  const contractDataOrInfo = options.includeBytecode
193
217
  ? await client.getContractData(address)
194
218
  : await client.getContractInfo(address);
195
219
 
196
220
  if (!contractDataOrInfo) {
197
- log(`No contract data found at ${_contractAddress}`);
221
+ log(`No contract data found at ${contractAddress}`);
198
222
  return;
199
223
  }
200
224
  let contractData: ContractData;
@@ -238,8 +262,26 @@ async function main() {
238
262
  }
239
263
  });
240
264
 
265
+ program
266
+ .command('register-public-key')
267
+ .description("Register an account's public key to the RPC server")
268
+ .option('-a, --address <aztecAddress>', "The account's Aztec address.")
269
+ .option('-p, --public-key <publicKey>', 'The account public key.')
270
+ .option('-pa, --partial-address <partialAddress', 'The partially computed address of the account contract.')
271
+ .option('-u, --rpc-url <string>', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080')
272
+ .action(async options => {
273
+ const client = createAztecRpcClient(options.rpcUrl);
274
+ const address = AztecAddress.fromString(options.address);
275
+ const publicKey = Point.fromString(options.publicKey);
276
+ const partialAddress = Fr.fromString(options.partialAddress);
277
+
278
+ await client.addPublicKeyAndPartialAddress(address, publicKey, partialAddress);
279
+ log(`\nRegistered details for Address: ${options.address}\n`);
280
+ });
281
+
241
282
  program
242
283
  .command('get-accounts')
284
+ .description('Gets all the Aztec accounts stored in the Aztec RPC.')
243
285
  .option('-u, --rpc-url <string>', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080')
244
286
  .action(async (options: any) => {
245
287
  const client = createAztecRpcClient(options.rpcUrl);
@@ -277,22 +319,33 @@ async function main() {
277
319
  program
278
320
  .command('send')
279
321
  .description('Calls a function on an Aztec contract.')
280
- .argument('<contractAbi>', "The compiled contract's ABI in JSON format", undefined)
281
- .argument('<contractAddress>', 'Address of the contract')
282
322
  .argument('<functionName>', 'Name of Function to view')
283
- .argument('[functionArgs...]', 'Function arguments', [])
323
+ .option('-a, --args [functionArgs...]', 'Function arguments', [])
324
+ .option(
325
+ '-c, --contract-abi <fileLocation>',
326
+ "A compiled Noir contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts",
327
+ undefined,
328
+ )
329
+ .option('-ca, --contract-address <address>', 'Aztec address of the contract.')
284
330
  .option('-k, --private-key <string>', "The sender's private key.", PRIVATE_KEY)
285
331
  .option('-u, --rpcUrl <string>', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080')
286
332
 
287
- .action(async (contractFile, _contractAddress, functionName, _functionArgs, options) => {
288
- const { contractAddress, functionArgs, contractAbi } = prepTx(
289
- contractFile,
290
- _contractAddress,
333
+ .action(async (functionName, options) => {
334
+ const { contractAddress, functionArgs, contractAbi } = await prepTx(
335
+ options.contractAbi,
336
+ options.contractAddress,
291
337
  functionName,
292
- _functionArgs,
338
+ options.args,
293
339
  log,
294
340
  );
295
341
 
342
+ const fnAbi = getAbiFunction(contractAbi, functionName);
343
+ if (fnAbi.parameters.length !== options.args.length) {
344
+ throw Error(
345
+ `Invalid number of args passed. Expected ${fnAbi.parameters.length}; Received: ${options.args.length}`,
346
+ );
347
+ }
348
+
296
349
  const client = createAztecRpcClient(options.rpcUrl);
297
350
  const wallet = await getAccountWallet(
298
351
  client,
@@ -319,20 +372,30 @@ async function main() {
319
372
  .description(
320
373
  'Simulates the execution of a view (read-only) function on a deployed contract, without modifying state.',
321
374
  )
322
- .argument('<contractAbi>', "The compiled contract's ABI in JSON format", undefined)
323
- .argument('<contractAddress>', 'Address of the contract')
324
375
  .argument('<functionName>', 'Name of Function to view')
325
- .argument('[functionArgs...]', 'Function arguments', [])
376
+ .option('-a, --args [functionArgs...]', 'Function arguments', [])
377
+ .option(
378
+ '-c, --contract-abi <fileLocation>',
379
+ "A compiled Noir contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts",
380
+ undefined,
381
+ )
382
+ .option('-ca, --contract-address <address>', 'Aztec address of the contract.')
326
383
  .option('-f, --from <string>', 'Public key of the TX viewer. If empty, will try to find account in RPC.')
327
384
  .option('-u, --rpcUrl <string>', 'URL of the Aztec RPC', AZTEC_RPC_HOST || 'http://localhost:8080')
328
- .action(async (contractFile, _contractAddress, functionName, _functionArgs, options) => {
329
- const { contractAddress, functionArgs } = prepTx(
330
- contractFile,
331
- _contractAddress,
385
+ .action(async (functionName, options) => {
386
+ const { contractAddress, functionArgs, contractAbi } = await prepTx(
387
+ options.contractAbi,
388
+ options.contractAddress,
332
389
  functionName,
333
- _functionArgs,
390
+ options.args,
334
391
  log,
335
392
  );
393
+ const fnAbi = getAbiFunction(contractAbi, functionName);
394
+ if (fnAbi.parameters.length !== options.args.length) {
395
+ throw Error(
396
+ `Invalid number of args passed. Expected ${fnAbi.parameters.length}; Received: ${options.args.length}`,
397
+ );
398
+ }
336
399
  const client = createAztecRpcClient(options.rpcUrl);
337
400
  const from = await getTxSender(client, options.from);
338
401
  const result = await client.viewTx(functionName, functionArgs, contractAddress, from);
@@ -344,16 +407,20 @@ async function main() {
344
407
  .command('parse-parameter-struct')
345
408
  .description("Helper for parsing an encoded string into a contract's parameter struct.")
346
409
  .argument('<encodedString>', 'The encoded hex string')
347
- .argument('<contractAbi>', "The compiled contract's ABI in JSON format")
348
- .argument('<parameterName>', 'The name of the struct parameter to decode into')
349
- .action((encodedString, contractFile, parameterName) => {
350
- const contractAbi = getContractAbi(contractFile, log);
410
+ .option(
411
+ '-c, --contract-abi <fileLocation>',
412
+ "A compiled Noir contract's ABI in JSON format or name of a contract ABI exported by @aztec/noir-contracts",
413
+ undefined,
414
+ )
415
+ .option('-p, --parameter <parameterName>', 'The name of the struct parameter to decode into')
416
+ .action(async (encodedString, options) => {
417
+ const contractAbi = await getContractAbi(options.contractAbi, log);
351
418
  const parameterAbitype = contractAbi.functions
352
419
  .map(({ parameters }) => parameters)
353
420
  .flat()
354
- .find(({ name, type }) => name === parameterName && type.kind === 'struct');
421
+ .find(({ name, type }) => name === options.parameter && type.kind === 'struct');
355
422
  if (!parameterAbitype) {
356
- log(`No struct parameter found with name ${parameterName}`);
423
+ log(`No struct parameter found with name ${options.parameter}`);
357
424
  return;
358
425
  }
359
426
  const data = parseStructString(encodedString, parameterAbitype.type as StructType);
@@ -370,6 +437,15 @@ async function main() {
370
437
  log(`${num}\n`);
371
438
  });
372
439
 
440
+ program
441
+ .command('example-contracts')
442
+ .description('Lists the example contracts available to deploy from @aztec/noir-contracts')
443
+ .action(async () => {
444
+ const abisList = await getExampleContractArtifacts();
445
+ const names = Object.keys(abisList);
446
+ names.forEach(name => log(name));
447
+ });
448
+
373
449
  await program.parseAsync(process.argv);
374
450
  }
375
451
 
package/src/utils.ts CHANGED
@@ -8,6 +8,27 @@ import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
8
8
 
9
9
  import { encodeArgs } from './cli_encoder.js';
10
10
 
11
+ /**
12
+ * Helper type to dynamically import contarcts.
13
+ */
14
+ interface ArtifactsType {
15
+ [key: string]: ContractAbi;
16
+ }
17
+
18
+ /**
19
+ * Helper to get an ABI function or throw error if it doesn't exist.
20
+ * @param abi - Contract's ABI in JSON format.
21
+ * @param fnName - Function name to be found.
22
+ * @returns The function's ABI.
23
+ */
24
+ export function getAbiFunction(abi: ContractAbi, fnName: string) {
25
+ const fn = abi.functions.find(({ name }) => name === fnName);
26
+ if (!fn) {
27
+ throw Error(`Function ${fnName} not found in contract ABI.`);
28
+ }
29
+ return fn;
30
+ }
31
+
11
32
  /**
12
33
  * Function to execute the 'deployRollupContracts' command.
13
34
  * @param rpcUrl - The RPC URL of the ethereum node.
@@ -27,13 +48,35 @@ export async function deployAztecContracts(
27
48
  return await deployL1Contracts(chain.rpcUrl, account, chain.chainInfo, debugLogger);
28
49
  }
29
50
 
51
+ /**
52
+ * Gets all contracts available in \@aztec/noir-contracts.
53
+ * @returns The contract ABIs.
54
+ */
55
+ export async function getExampleContractArtifacts() {
56
+ const artifacts: ArtifactsType = await import('@aztec/noir-contracts/artifacts');
57
+ return artifacts;
58
+ }
59
+
30
60
  /**
31
61
  * Reads a file and converts it to an Aztec Contract ABI.
32
62
  * @param fileDir - The directory of the compiled contract ABI.
33
63
  * @returns The parsed ContractABI.
34
64
  */
35
- export function getContractAbi(fileDir: string, log: LogFn) {
36
- const contents = fs.readFileSync(fileDir, 'utf8');
65
+ export async function getContractAbi(fileDir: string, log: LogFn) {
66
+ // first check if it's a noir-contracts example
67
+ let contents: string;
68
+ const artifacts = await getExampleContractArtifacts();
69
+ if (artifacts[fileDir]) {
70
+ return artifacts[fileDir] as ContractAbi;
71
+ }
72
+
73
+ try {
74
+ contents = fs.readFileSync(fileDir, 'utf8');
75
+ } catch {
76
+ throw Error(`Contract ${fileDir} not found`);
77
+ }
78
+
79
+ // if not found, try reading as path directly
37
80
  let contractAbi: ContractAbi;
38
81
  try {
39
82
  contractAbi = JSON.parse(contents) as ContractAbi;
@@ -78,7 +121,7 @@ export async function getTxSender(client: AztecRPC, _from?: string) {
78
121
  * @param log - Logger instance that will output to the CLI
79
122
  * @returns Formatted contract address, function arguments and caller's aztec address.
80
123
  */
81
- export function prepTx(
124
+ export async function prepTx(
82
125
  contractFile: string,
83
126
  _contractAddress: string,
84
127
  functionName: string,
@@ -91,12 +134,8 @@ export function prepTx(
91
134
  } catch {
92
135
  throw new Error(`Unable to parse contract address ${_contractAddress}.`);
93
136
  }
94
- const contractAbi = getContractAbi(contractFile, log);
95
- const functionAbi = contractAbi.functions.find(({ name }) => name === functionName);
96
- if (!functionAbi) {
97
- throw new Error(`Function ${functionName} not found on contract ABI.`);
98
- }
99
-
137
+ const contractAbi = await getContractAbi(contractFile, log);
138
+ const functionAbi = getAbiFunction(contractAbi, functionName);
100
139
  const functionArgs = encodeArgs(_functionArgs, functionAbi.parameters);
101
140
 
102
141
  return { contractAddress, functionArgs, contractAbi };