@aztec/cli-wallet 0.0.1-commit.a072138 → 0.0.1-commit.a4600f49

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.
Files changed (57) hide show
  1. package/dest/bin/index.js +1 -1
  2. package/dest/cmds/authorize_action.d.ts +2 -2
  3. package/dest/cmds/authorize_action.d.ts.map +1 -1
  4. package/dest/cmds/check_tx.d.ts +1 -1
  5. package/dest/cmds/check_tx.d.ts.map +1 -1
  6. package/dest/cmds/check_tx.js +50 -21
  7. package/dest/cmds/create_account.d.ts +4 -3
  8. package/dest/cmds/create_account.d.ts.map +1 -1
  9. package/dest/cmds/create_account.js +36 -26
  10. package/dest/cmds/deploy.d.ts +5 -4
  11. package/dest/cmds/deploy.d.ts.map +1 -1
  12. package/dest/cmds/deploy.js +44 -38
  13. package/dest/cmds/deploy_account.d.ts +4 -3
  14. package/dest/cmds/deploy_account.d.ts.map +1 -1
  15. package/dest/cmds/deploy_account.js +28 -20
  16. package/dest/cmds/get_fee_juice_balance.d.ts +5 -0
  17. package/dest/cmds/get_fee_juice_balance.d.ts.map +1 -0
  18. package/dest/cmds/get_fee_juice_balance.js +27 -0
  19. package/dest/cmds/import_test_accounts.d.ts +1 -1
  20. package/dest/cmds/import_test_accounts.d.ts.map +1 -1
  21. package/dest/cmds/import_test_accounts.js +1 -1
  22. package/dest/cmds/index.d.ts +1 -1
  23. package/dest/cmds/index.d.ts.map +1 -1
  24. package/dest/cmds/index.js +31 -15
  25. package/dest/cmds/send.d.ts +4 -3
  26. package/dest/cmds/send.d.ts.map +1 -1
  27. package/dest/cmds/send.js +28 -27
  28. package/dest/cmds/simulate.d.ts +1 -1
  29. package/dest/cmds/simulate.d.ts.map +1 -1
  30. package/dest/cmds/simulate.js +2 -1
  31. package/dest/storage/wallet_db.d.ts +7 -2
  32. package/dest/storage/wallet_db.d.ts.map +1 -1
  33. package/dest/storage/wallet_db.js +14 -0
  34. package/dest/utils/constants.d.ts +2 -2
  35. package/dest/utils/constants.d.ts.map +1 -1
  36. package/dest/utils/constants.js +1 -0
  37. package/dest/utils/options/fees.d.ts +3 -2
  38. package/dest/utils/options/fees.d.ts.map +1 -1
  39. package/dest/utils/options/fees.js +36 -10
  40. package/dest/utils/wallet.d.ts +24 -6
  41. package/dest/utils/wallet.d.ts.map +1 -1
  42. package/dest/utils/wallet.js +135 -60
  43. package/package.json +16 -15
  44. package/src/bin/index.ts +1 -1
  45. package/src/cmds/check_tx.ts +57 -24
  46. package/src/cmds/create_account.ts +36 -20
  47. package/src/cmds/deploy.ts +41 -33
  48. package/src/cmds/deploy_account.ts +27 -14
  49. package/src/cmds/get_fee_juice_balance.ts +37 -0
  50. package/src/cmds/import_test_accounts.ts +5 -1
  51. package/src/cmds/index.ts +60 -6
  52. package/src/cmds/send.ts +25 -17
  53. package/src/cmds/simulate.ts +3 -2
  54. package/src/storage/wallet_db.ts +14 -0
  55. package/src/utils/constants.ts +7 -1
  56. package/src/utils/options/fees.ts +42 -10
  57. package/src/utils/wallet.ts +148 -76
@@ -1,11 +1,15 @@
1
1
  import type { ContractArtifact } from '@aztec/aztec.js/abi';
2
- import type { AztecAddress } from '@aztec/aztec.js/addresses';
2
+ import { AztecAddress } from '@aztec/aztec.js/addresses';
3
3
  import { Fr } from '@aztec/aztec.js/fields';
4
4
  import type { AztecNode } from '@aztec/aztec.js/node';
5
5
  import { ProtocolContractAddress } from '@aztec/aztec.js/protocol';
6
6
  import type { TxHash } from '@aztec/aztec.js/tx';
7
7
  import type { LogFn } from '@aztec/foundation/log';
8
- import { siloNullifier } from '@aztec/stdlib/hash';
8
+ import {
9
+ computeSiloedPrivateInitializationNullifier,
10
+ computeSiloedPublicInitializationNullifier,
11
+ siloNullifier,
12
+ } from '@aztec/stdlib/hash';
9
13
  import { NoteDao } from '@aztec/stdlib/note';
10
14
 
11
15
  import type { CLIWallet } from '../utils/wallet.js';
@@ -29,7 +33,7 @@ export async function checkTx(
29
33
  // dependency when dropping PXE JSON RPC Server.
30
34
 
31
35
  async function inspectTx(wallet: CLIWallet, aztecNode: AztecNode, txHash: TxHash, log: LogFn) {
32
- const [receipt, effectsInBlock] = await Promise.all([aztecNode.getTxReceipt(txHash), aztecNode.getTxEffect(txHash)]);
36
+ const receipt = await aztecNode.getTxReceipt(txHash, { includeTxEffect: true });
33
37
  // Base tx data
34
38
  log(`Tx ${txHash.toString()}`);
35
39
  log(` Status: ${receipt.status}`);
@@ -40,11 +44,11 @@ async function inspectTx(wallet: CLIWallet, aztecNode: AztecNode, txHash: TxHash
40
44
  log(` Error: ${receipt.error}`);
41
45
  }
42
46
 
43
- if (!effectsInBlock) {
47
+ if (!receipt.isMined() || !receipt.txEffect) {
44
48
  return;
45
49
  }
46
50
 
47
- const effects = effectsInBlock.data;
51
+ const effects = receipt.txEffect;
48
52
  const artifactMap = await getKnownArtifacts(wallet);
49
53
 
50
54
  log(` Block: ${receipt.blockNumber} (${receipt.blockHash?.toString()})`);
@@ -83,12 +87,13 @@ async function inspectTx(wallet: CLIWallet, aztecNode: AztecNode, txHash: TxHash
83
87
  // Nullifiers
84
88
  const nullifierCount = effects.nullifiers.length;
85
89
  const { deployNullifiers, initNullifiers, classNullifiers } = await getKnownNullifiers(wallet, artifactMap);
90
+ const accounts = (await wallet.getAccounts()).map(a => a.item);
86
91
  if (nullifierCount > 0) {
87
92
  log(' Nullifiers:');
88
93
  for (const nullifier of effects.nullifiers) {
89
94
  const deployed = deployNullifiers[nullifier.toString()];
90
95
  const note = deployed
91
- ? (await wallet.getNotes({ siloedNullifier: nullifier, contractAddress: deployed }))[0]
96
+ ? (await wallet.getNotes({ siloedNullifier: nullifier, contractAddress: deployed, scopes: accounts }))[0]
92
97
  : undefined;
93
98
  const initialized = initNullifiers[nullifier.toString()];
94
99
  const registered = classNullifiers[nullifier.toString()];
@@ -144,42 +149,70 @@ function toFriendlyAddress(address: AztecAddress, artifactMap: ArtifactMap) {
144
149
 
145
150
  async function getKnownNullifiers(wallet: CLIWallet, artifactMap: ArtifactMap) {
146
151
  const knownContracts = await wallet.getContracts();
147
- const deployerAddress = ProtocolContractAddress.ContractInstanceRegistry;
148
- const classRegistryAddress = ProtocolContractAddress.ContractClassRegistry;
152
+
153
+ const [contractResults, classResults] = await Promise.all([
154
+ Promise.all(knownContracts.map(contract => getContractNullifiers(wallet, contract))),
155
+ Promise.all(Object.values(artifactMap).map(artifact => getClassNullifier(artifact))),
156
+ ]);
157
+
149
158
  const initNullifiers: Record<string, AztecAddress> = {};
150
159
  const deployNullifiers: Record<string, AztecAddress> = {};
151
160
  const classNullifiers: Record<string, string> = {};
152
- for (const contract of knownContracts) {
153
- initNullifiers[(await siloNullifier(contract, contract.toField())).toString()] = contract;
154
- deployNullifiers[(await siloNullifier(deployerAddress, contract.toField())).toString()] = contract;
161
+
162
+ for (const { contract, deployNullifier, privateInitNullifier, publicInitNullifier } of contractResults) {
163
+ deployNullifiers[deployNullifier.toString()] = contract;
164
+ if (privateInitNullifier) {
165
+ initNullifiers[privateInitNullifier.toString()] = contract;
166
+ }
167
+ initNullifiers[publicInitNullifier.toString()] = contract;
155
168
  }
156
- for (const artifact of Object.values(artifactMap)) {
157
- classNullifiers[(await siloNullifier(classRegistryAddress, artifact.classId)).toString()] =
158
- `${artifact.name}Class<${artifact.classId}>`;
169
+ for (const { nullifier, label } of classResults) {
170
+ classNullifiers[nullifier.toString()] = label;
159
171
  }
172
+
160
173
  return { initNullifiers, deployNullifiers, classNullifiers };
161
174
  }
162
175
 
176
+ async function getContractNullifiers(wallet: CLIWallet, contract: AztecAddress) {
177
+ const deployerAddress = ProtocolContractAddress.ContractInstanceRegistry;
178
+ const deployNullifier = await siloNullifier(deployerAddress, contract.toField());
179
+
180
+ const metadata = await wallet.getContractMetadata(contract);
181
+ const privateInitNullifier = metadata.instance
182
+ ? await computeSiloedPrivateInitializationNullifier(contract, metadata.instance.initializationHash)
183
+ : undefined;
184
+ const publicInitNullifier = await computeSiloedPublicInitializationNullifier(contract);
185
+
186
+ return { contract, deployNullifier, privateInitNullifier, publicInitNullifier };
187
+ }
188
+
189
+ async function getClassNullifier(artifact: ContractArtifactWithClassId) {
190
+ const classRegistryAddress = ProtocolContractAddress.ContractClassRegistry;
191
+ const nullifier = await siloNullifier(classRegistryAddress, artifact.classId);
192
+ return { nullifier, label: `${artifact.name}Class<${artifact.classId}>` };
193
+ }
194
+
163
195
  type ArtifactMap = Record<string, ContractArtifactWithClassId>;
164
196
  type ContractArtifactWithClassId = ContractArtifact & { classId: Fr };
165
197
 
166
198
  async function getKnownArtifacts(wallet: CLIWallet): Promise<ArtifactMap> {
167
199
  const knownContractAddresses = await wallet.getContracts();
168
- const knownContracts = (
169
- await Promise.all(knownContractAddresses.map(contractAddress => wallet.getContractMetadata(contractAddress)))
170
- ).map(contractMetadata => contractMetadata.instance);
171
- const classIds = [...new Set(knownContracts.map(contract => contract?.currentContractClassId))];
200
+ const knownContracts = await Promise.all(
201
+ knownContractAddresses.map(contractAddress => wallet.getContractMetadata(contractAddress)),
202
+ );
203
+ const classIdFor = (metadata: (typeof knownContracts)[number]): Fr | undefined =>
204
+ metadata.updatedContractClassId ?? metadata.instance?.originalContractClassId;
205
+ const classIds = [...new Set(knownContracts.map(classIdFor))];
172
206
  const knownArtifacts = (
173
207
  await Promise.all(classIds.map(classId => (classId ? wallet.getContractArtifact(classId) : undefined)))
174
208
  ).map((artifact, index) => (artifact ? { ...artifact, classId: classIds[index] } : undefined));
175
209
  const map: Record<string, ContractArtifactWithClassId> = {};
176
- for (const instance of knownContracts) {
177
- if (instance) {
178
- const artifact = knownArtifacts.find(a =>
179
- a?.classId?.equals(instance.currentContractClassId),
180
- ) as ContractArtifactWithClassId;
210
+ for (const metadata of knownContracts) {
211
+ const classId = classIdFor(metadata);
212
+ if (metadata.instance && classId) {
213
+ const artifact = knownArtifacts.find(a => a?.classId?.equals(classId)) as ContractArtifactWithClassId;
181
214
  if (artifact) {
182
- map[instance.address.toString()] = artifact;
215
+ map[metadata.instance.address.toString()] = artifact;
183
216
  }
184
217
  }
185
218
  }
@@ -1,11 +1,12 @@
1
+ import { NO_FROM } from '@aztec/aztec.js/account';
1
2
  import { AztecAddress } from '@aztec/aztec.js/addresses';
2
3
  import { NO_WAIT } from '@aztec/aztec.js/contracts';
3
- import type { AztecNode } from '@aztec/aztec.js/node';
4
+ import { type AztecNode, waitForTx } from '@aztec/aztec.js/node';
4
5
  import type { DeployAccountOptions } from '@aztec/aztec.js/wallet';
5
6
  import { prettyPrintJSON } from '@aztec/cli/cli-utils';
6
7
  import { Fr } from '@aztec/foundation/curves/bn254';
7
8
  import type { LogFn, Logger } from '@aztec/foundation/log';
8
- import type { TxHash, TxReceipt } from '@aztec/stdlib/tx';
9
+ import { type TxHash, type TxReceipt, TxStatus } from '@aztec/stdlib/tx';
9
10
 
10
11
  import { DEFAULT_TX_TIMEOUT_S } from '../utils/cli_wallet_and_node_wrapper.js';
11
12
  import type { AccountType } from '../utils/constants.js';
@@ -18,6 +19,7 @@ export async function createAccount(
18
19
  aztecNode: AztecNode,
19
20
  accountType: AccountType,
20
21
  secretKey: Fr | undefined,
22
+ salt: Fr | undefined,
21
23
  publicKey: string | undefined,
22
24
  alias: string | undefined,
23
25
  deployer: AztecAddress | undefined,
@@ -27,6 +29,7 @@ export async function createAccount(
27
29
  registerClass: boolean,
28
30
  wait: boolean,
29
31
  feeOpts: CLIFeeArgs,
32
+ waitForStatus: TxStatus,
30
33
  json: boolean,
31
34
  verbose: boolean,
32
35
  debugLogger: Logger,
@@ -38,10 +41,10 @@ export async function createAccount(
38
41
  undefined /* address, we don't have it yet */,
39
42
  secretKey,
40
43
  accountType,
41
- Fr.ZERO,
44
+ salt,
42
45
  publicKey,
43
46
  );
44
- const { salt } = account.getInstance();
47
+ const instanceSalt = account.getInstance().salt;
45
48
  const { address, publicKeys, partialAddress } = await account.getCompleteAddress();
46
49
 
47
50
  const out: Record<string, any> = {};
@@ -52,7 +55,7 @@ export async function createAccount(
52
55
  out.secretKey = secretKey;
53
56
  }
54
57
  out.partialAddress = partialAddress;
55
- out.salt = salt;
58
+ out.salt = instanceSalt;
56
59
  out.initHash = account.getInstance().initializationHash;
57
60
  } else {
58
61
  log(`\nNew account:\n`);
@@ -62,17 +65,19 @@ export async function createAccount(
62
65
  log(`Secret key: ${secretKey.toString()}`);
63
66
  }
64
67
  log(`Partial address: ${partialAddress.toString()}`);
65
- log(`Salt: ${salt.toString()}`);
68
+ log(`Salt: ${instanceSalt.toString()}`);
66
69
  log(`Init hash: ${account.getInstance().initializationHash.toString()}`);
67
70
  }
68
71
 
69
72
  let txHash: TxHash | undefined;
70
73
  let txReceipt: TxReceipt | undefined;
71
- if (!registerOnly) {
74
+ // Initializerless accounts have no deployment tx — creating one only registers it locally — so there is
75
+ // nothing to deploy on-chain.
76
+ if (!registerOnly && accountType !== 'schnorr_initializerless') {
72
77
  const { paymentMethod, gasSettings } = await feeOpts.toUserFeeOptions(aztecNode, wallet, address);
73
78
 
74
79
  const delegatedDeployment = deployer && !account.address.equals(deployer);
75
- const from = delegatedDeployment ? deployer : AztecAddress.ZERO;
80
+ const from = delegatedDeployment ? deployer : NO_FROM;
76
81
 
77
82
  const deployAccountOpts: DeployAccountOptions = {
78
83
  skipClassPublication: !registerClass,
@@ -82,11 +87,15 @@ export async function createAccount(
82
87
  fee: { paymentMethod, gasSettings },
83
88
  };
84
89
 
90
+ const localStart = performance.now();
85
91
  const deployMethod = await account.getDeployMethod();
86
- const { estimatedGas, stats } = await deployMethod.simulate({
92
+ const sim = await deployMethod.simulate({
87
93
  ...deployAccountOpts,
88
- fee: { ...deployAccountOpts.fee, estimateGas: true },
94
+ includeMetadata: true,
89
95
  });
96
+ // includeMetadata: true guarantees these fields are present
97
+ const estimatedGas = await wallet.estimateGasLimits(sim.gasUsed!);
98
+ const stats = sim.stats!;
90
99
 
91
100
  if (feeOpts.estimateOnly) {
92
101
  if (json) {
@@ -109,7 +118,7 @@ export async function createAccount(
109
118
  if (!json) {
110
119
  log(`\nWaiting for account contract deployment...`);
111
120
  }
112
- const result = await deployMethod.send({
121
+ const sendOpts = {
113
122
  ...deployAccountOpts,
114
123
  fee: deployAccountOpts.fee
115
124
  ? {
@@ -117,18 +126,25 @@ export async function createAccount(
117
126
  gasSettings: estimatedGas,
118
127
  }
119
128
  : undefined,
120
- wait: wait ? { timeout: DEFAULT_TX_TIMEOUT_S, returnReceipt: true } : NO_WAIT,
121
- });
122
- const isReceipt = (data: TxReceipt | TxHash): data is TxReceipt => 'txHash' in data;
123
- if (isReceipt(result)) {
124
- txReceipt = result;
125
- txHash = result.txHash;
129
+ };
130
+
131
+ ({ txHash } = await deployMethod.send({ ...sendOpts, wait: NO_WAIT }));
132
+ const localTimeMs = performance.now() - localStart;
133
+
134
+ if (wait) {
135
+ const nodeStart = performance.now();
136
+ txReceipt = await waitForTx(aztecNode, txHash, { timeout: DEFAULT_TX_TIMEOUT_S, waitForStatus });
137
+ const nodeTimeMs = performance.now() - nodeStart;
138
+
126
139
  out.txReceipt = {
127
140
  status: txReceipt.status,
128
141
  transactionFee: txReceipt.transactionFee,
129
142
  };
130
- } else {
131
- txHash = result;
143
+
144
+ if (!json) {
145
+ log(` Local processing time: ${(localTimeMs / 1000).toFixed(1)}s`);
146
+ log(` Node inclusion time: ${(nodeTimeMs / 1000).toFixed(1)}s`);
147
+ }
132
148
  }
133
149
  debugLogger.debug(`Account contract tx sent with hash ${txHash.toString()}`);
134
150
  out.txHash = txHash;
@@ -146,5 +162,5 @@ export async function createAccount(
146
162
  }
147
163
  }
148
164
 
149
- return { alias, address, secretKey, salt };
165
+ return { alias, address, secretKey, salt: instanceSalt };
150
166
  }
@@ -1,13 +1,15 @@
1
- import { AztecAddress } from '@aztec/aztec.js/addresses';
1
+ import { NO_FROM } from '@aztec/aztec.js/account';
2
+ import type { AztecAddress } from '@aztec/aztec.js/addresses';
2
3
  import type { DeployOptions } from '@aztec/aztec.js/contracts';
3
4
  import { NO_WAIT } from '@aztec/aztec.js/contracts';
4
5
  import { ContractDeployer } from '@aztec/aztec.js/deployment';
5
6
  import { Fr } from '@aztec/aztec.js/fields';
6
- import type { AztecNode } from '@aztec/aztec.js/node';
7
+ import { type AztecNode, waitForTx } from '@aztec/aztec.js/node';
7
8
  import { encodeArgs, getContractArtifact, prettyPrintJSON } from '@aztec/cli/utils';
8
9
  import type { LogFn, Logger } from '@aztec/foundation/log';
9
10
  import { getAllFunctionAbis, getInitializer } from '@aztec/stdlib/abi';
10
11
  import { PublicKeys } from '@aztec/stdlib/keys';
12
+ import type { TxStatus } from '@aztec/stdlib/tx';
11
13
 
12
14
  import { DEFAULT_TX_TIMEOUT_S } from '../utils/cli_wallet_and_node_wrapper.js';
13
15
  import { CLIFeeArgs } from '../utils/options/fees.js';
@@ -29,10 +31,12 @@ export async function deploy(
29
31
  skipInitialization: boolean | undefined,
30
32
  wait: boolean,
31
33
  feeOpts: CLIFeeArgs,
34
+ waitForStatus: TxStatus,
32
35
  verbose: boolean,
33
36
  timeout: number = DEFAULT_TX_TIMEOUT_S,
34
37
  debugLogger: Logger,
35
38
  log: LogFn,
39
+ universal?: boolean,
36
40
  ) {
37
41
  const out: Record<string, any> = {};
38
42
  salt ??= Fr.random();
@@ -42,12 +46,7 @@ export async function deploy(
42
46
 
43
47
  // TODO(#12081): Add contractArtifact.noirVersion and check here (via Noir.lock)?
44
48
 
45
- const contractDeployer = new ContractDeployer(
46
- contractArtifact,
47
- wallet,
48
- publicKeys ?? PublicKeys.default(),
49
- initializer,
50
- );
49
+ const contractDeployer = new ContractDeployer(contractArtifact, wallet, initializer);
51
50
 
52
51
  let args = [];
53
52
  if (rawArgs.length > 0) {
@@ -59,22 +58,28 @@ export async function deploy(
59
58
  debugLogger.debug(`Encoded arguments: ${args.join(', ')}`);
60
59
  }
61
60
 
62
- const deploy = contractDeployer.deploy(...args);
61
+ const deployInteraction = contractDeployer.deploy(args, {
62
+ salt,
63
+ publicKeys: publicKeys ?? PublicKeys.default(),
64
+ ...(universal ? { universalDeploy: true as const } : {}),
65
+ });
63
66
  const { paymentMethod, gasSettings } = await feeOpts.toUserFeeOptions(node, wallet, deployer);
64
67
  const deployOpts: DeployOptions = {
65
68
  fee: { gasSettings, paymentMethod },
66
- from: deployer ?? AztecAddress.ZERO,
67
- contractAddressSalt: salt,
68
- universalDeploy: !deployer,
69
+ from: deployer ?? NO_FROM,
69
70
  skipClassPublication,
70
71
  skipInitialization,
71
72
  skipInstancePublication,
72
73
  };
73
74
 
74
- const { estimatedGas, stats } = await deploy.simulate({
75
+ const localStart = performance.now();
76
+ const sim = await deployInteraction.simulate({
75
77
  ...deployOpts,
76
- fee: { ...deployOpts.fee, estimateGas: true },
78
+ includeMetadata: true,
77
79
  });
80
+ // includeMetadata: true guarantees these fields are present
81
+ const estimatedGas = await wallet.estimateGasLimits(sim.gasUsed!);
82
+ const stats = sim.stats!;
78
83
 
79
84
  if (feeOpts.estimateOnly) {
80
85
  if (json) {
@@ -94,48 +99,51 @@ export async function deploy(
94
99
  printProfileResult(stats, log);
95
100
  }
96
101
 
97
- const { address, partialAddress } = deploy;
98
- const instance = await deploy.getInstance();
102
+ const instance = await deployInteraction.getInstance();
103
+ const address = instance.address;
104
+ const partialAddress = await deployInteraction.getPartialAddress();
105
+
106
+ const { txHash } = await deployInteraction.send({ ...deployOpts, wait: NO_WAIT });
107
+ const localTimeMs = performance.now() - localStart;
108
+ debugLogger.debug(`Deploy tx sent with hash ${txHash.toString()}`);
109
+ out.hash = txHash;
99
110
 
100
111
  if (wait) {
101
- const receipt = await deploy.send({ ...deployOpts, wait: { timeout, returnReceipt: true } });
102
- const txHash = receipt.txHash;
103
- debugLogger.debug(`Deploy tx sent with hash ${txHash.toString()}`);
104
- out.hash = txHash;
112
+ const nodeStart = performance.now();
113
+ const receipt = await waitForTx(node, txHash, { timeout, waitForStatus });
114
+ const nodeTimeMs = performance.now() - nodeStart;
105
115
 
106
116
  if (!json) {
107
- log(`Contract deployed at ${address?.toString()}`);
108
- log(`Contract partial address ${(await partialAddress)?.toString()}`);
117
+ log(`Contract deployed at ${address.toString()}`);
118
+ log(`Contract partial address ${partialAddress.toString()}`);
109
119
  log(`Contract init hash ${instance.initializationHash.toString()}`);
110
120
  log(`Deployment tx hash: ${txHash.toString()}`);
111
121
  log(`Deployment salt: ${salt.toString()}`);
112
122
  log(`Deployer: ${instance.deployer.toString()}`);
113
123
  log(`Transaction fee: ${receipt.transactionFee?.toString()}`);
124
+ log(` Local processing time: ${(localTimeMs / 1000).toFixed(1)}s`);
125
+ log(` Node inclusion time: ${(nodeTimeMs / 1000).toFixed(1)}s`);
114
126
  } else {
115
127
  out.contract = {
116
- address: address?.toString(),
117
- partialAddress: (await partialAddress)?.toString(),
128
+ address: address.toString(),
129
+ partialAddress: partialAddress.toString(),
118
130
  initializationHash: instance.initializationHash.toString(),
119
131
  salt: salt.toString(),
120
132
  transactionFee: receipt.transactionFee?.toString(),
121
133
  };
122
134
  }
123
135
  } else {
124
- const txHash = await deploy.send({ ...deployOpts, wait: NO_WAIT });
125
- debugLogger.debug(`Deploy tx sent with hash ${txHash.toString()}`);
126
- out.hash = txHash;
127
-
128
136
  if (!json) {
129
- log(`Contract deployed at ${address?.toString()}`);
130
- log(`Contract partial address ${(await partialAddress)?.toString()}`);
137
+ log(`Contract deployed at ${address.toString()}`);
138
+ log(`Contract partial address ${partialAddress.toString()}`);
131
139
  log(`Contract init hash ${instance.initializationHash.toString()}`);
132
140
  log(`Deployment tx hash: ${txHash.toString()}`);
133
141
  log(`Deployment salt: ${salt.toString()}`);
134
142
  log(`Deployer: ${instance.deployer.toString()}`);
135
143
  } else {
136
144
  out.contract = {
137
- address: address?.toString(),
138
- partialAddress: (await partialAddress)?.toString(),
145
+ address: address.toString(),
146
+ partialAddress: partialAddress.toString(),
139
147
  initializationHash: instance.initializationHash.toString(),
140
148
  salt: salt.toString(),
141
149
  };
@@ -145,5 +153,5 @@ export async function deploy(
145
153
  if (json) {
146
154
  log(prettyPrintJSON(out));
147
155
  }
148
- return deploy.address;
156
+ return await deployInteraction.getAddress();
149
157
  }
@@ -1,10 +1,11 @@
1
+ import { NO_FROM } from '@aztec/aztec.js/account';
1
2
  import { AztecAddress } from '@aztec/aztec.js/addresses';
2
3
  import { NO_WAIT } from '@aztec/aztec.js/contracts';
3
- import type { AztecNode } from '@aztec/aztec.js/node';
4
+ import { type AztecNode, waitForTx } from '@aztec/aztec.js/node';
4
5
  import type { DeployAccountOptions } from '@aztec/aztec.js/wallet';
5
6
  import { prettyPrintJSON } from '@aztec/cli/cli-utils';
6
7
  import type { LogFn, Logger } from '@aztec/foundation/log';
7
- import type { TxHash, TxReceipt } from '@aztec/stdlib/tx';
8
+ import type { TxHash, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
8
9
 
9
10
  import { DEFAULT_TX_TIMEOUT_S } from '../utils/cli_wallet_and_node_wrapper.js';
10
11
  import type { CLIFeeArgs } from '../utils/options/fees.js';
@@ -21,6 +22,7 @@ export async function deployAccount(
21
22
  publicDeploy: boolean,
22
23
  skipInitialization: boolean,
23
24
  feeOpts: CLIFeeArgs,
25
+ waitForStatus: TxStatus,
24
26
  json: boolean,
25
27
  verbose: boolean,
26
28
  debugLogger: Logger,
@@ -52,7 +54,7 @@ export async function deployAccount(
52
54
  const { paymentMethod, gasSettings } = await feeOpts.toUserFeeOptions(aztecNode, wallet, address);
53
55
 
54
56
  const delegatedDeployment = deployer && !account.address.equals(deployer);
55
- const from = delegatedDeployment ? deployer : AztecAddress.ZERO;
57
+ const from = delegatedDeployment ? deployer : NO_FROM;
56
58
 
57
59
  const deployAccountOpts: DeployAccountOptions = {
58
60
  skipClassPublication: !registerClass,
@@ -62,11 +64,15 @@ export async function deployAccount(
62
64
  fee: { paymentMethod, gasSettings },
63
65
  };
64
66
 
67
+ const localStart = performance.now();
65
68
  const deployMethod = await account.getDeployMethod();
66
- const { estimatedGas, stats } = await deployMethod.simulate({
69
+ const sim = await deployMethod.simulate({
67
70
  ...deployAccountOpts,
68
- fee: { ...deployAccountOpts.fee, estimateGas: true },
71
+ includeMetadata: true,
69
72
  });
73
+ // includeMetadata: true guarantees these fields are present
74
+ const estimatedGas = await wallet.estimateGasLimits(sim.gasUsed!);
75
+ const stats = sim.stats!;
70
76
 
71
77
  if (feeOpts.estimateOnly) {
72
78
  if (json) {
@@ -89,7 +95,7 @@ export async function deployAccount(
89
95
  if (!json) {
90
96
  log(`\nWaiting for account contract deployment...`);
91
97
  }
92
- const result = await deployMethod.send({
98
+ const sendOpts = {
93
99
  ...deployAccountOpts,
94
100
  fee: deployAccountOpts.fee
95
101
  ? {
@@ -97,18 +103,25 @@ export async function deployAccount(
97
103
  gasSettings: estimatedGas,
98
104
  }
99
105
  : undefined,
100
- wait: wait ? { timeout: DEFAULT_TX_TIMEOUT_S, returnReceipt: true } : NO_WAIT,
101
- });
102
- const isReceipt = (data: TxReceipt | TxHash): data is TxReceipt => 'txHash' in data;
103
- if (isReceipt(result)) {
104
- txReceipt = result;
105
- txHash = result.txHash;
106
+ };
107
+
108
+ ({ txHash } = await deployMethod.send({ ...sendOpts, wait: NO_WAIT }));
109
+ const localTimeMs = performance.now() - localStart;
110
+
111
+ if (wait) {
112
+ const nodeStart = performance.now();
113
+ txReceipt = await waitForTx(aztecNode, txHash, { timeout: DEFAULT_TX_TIMEOUT_S, waitForStatus });
114
+ const nodeTimeMs = performance.now() - nodeStart;
115
+
106
116
  out.txReceipt = {
107
117
  status: txReceipt.status,
108
118
  transactionFee: txReceipt.transactionFee,
109
119
  };
110
- } else {
111
- txHash = result;
120
+
121
+ if (!json) {
122
+ log(` Local processing time: ${(localTimeMs / 1000).toFixed(1)}s`);
123
+ log(` Node inclusion time: ${(nodeTimeMs / 1000).toFixed(1)}s`);
124
+ }
112
125
  }
113
126
  debugLogger.debug(`Account contract tx sent with hash ${txHash.toString()}`);
114
127
  out.txHash = txHash;
@@ -0,0 +1,37 @@
1
+ import type { AztecAddress } from '@aztec/aztec.js/addresses';
2
+ import type { AztecNode } from '@aztec/aztec.js/node';
3
+ import { getFeeJuiceBalance } from '@aztec/aztec.js/utils';
4
+ import { prettyPrintJSON } from '@aztec/cli/cli-utils';
5
+ import type { LogFn } from '@aztec/foundation/log';
6
+
7
+ const FEE_JUICE_DECIMALS = 18;
8
+ const FEE_JUICE_UNIT = 10n ** BigInt(FEE_JUICE_DECIMALS);
9
+
10
+ /** Formats a raw FeeJuice balance (18 decimals) for human-readable display. */
11
+ function formatFeeJuice(raw: bigint, exact: boolean): string {
12
+ const whole = raw / FEE_JUICE_UNIT;
13
+ const fractional = raw % FEE_JUICE_UNIT;
14
+ const fracStr = fractional.toString().padStart(FEE_JUICE_DECIMALS, '0');
15
+ if (exact) {
16
+ return `${whole}.${fracStr} FJ`;
17
+ }
18
+ if (fractional === 0n) {
19
+ return `${whole} FJ`;
20
+ }
21
+ return `${whole}.${fracStr.replace(/0+$/, '')} FJ`;
22
+ }
23
+
24
+ export async function getFeeJuiceBalanceCmd(
25
+ node: AztecNode,
26
+ address: AztecAddress,
27
+ json: boolean,
28
+ exact: boolean,
29
+ log: LogFn,
30
+ ) {
31
+ const balance = await getFeeJuiceBalance(address, node);
32
+ if (json) {
33
+ log(prettyPrintJSON({ address: address.toString(), balance: balance.toString() }));
34
+ } else {
35
+ log(`Fee Juice balance for ${address.toString()}: ${formatFeeJuice(balance, exact)}`);
36
+ }
37
+ }
@@ -16,7 +16,11 @@ export async function importTestAccounts(wallet: CLIWallet, db: WalletDB, json:
16
16
  const secret = testAccounts[i].secret;
17
17
  const salt = new Fr(account.salt);
18
18
  const address = account.address;
19
- await db.storeAccount(address, { type: 'schnorr', secretKey: secret, salt, alias, publicKey: undefined }, log);
19
+ await db.storeAccount(
20
+ address,
21
+ { type: 'schnorr_initializerless', secretKey: secret, salt, alias, publicKey: undefined },
22
+ log,
23
+ );
20
24
 
21
25
  if (json) {
22
26
  out[alias] = {