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

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 (44) hide show
  1. package/dest/cmds/authorize_action.d.ts +2 -2
  2. package/dest/cmds/authorize_action.d.ts.map +1 -1
  3. package/dest/cmds/check_tx.d.ts +1 -1
  4. package/dest/cmds/check_tx.d.ts.map +1 -1
  5. package/dest/cmds/check_tx.js +37 -9
  6. package/dest/cmds/create_account.d.ts +4 -3
  7. package/dest/cmds/create_account.d.ts.map +1 -1
  8. package/dest/cmds/create_account.js +32 -21
  9. package/dest/cmds/deploy.d.ts +4 -3
  10. package/dest/cmds/deploy.d.ts.map +1 -1
  11. package/dest/cmds/deploy.js +27 -23
  12. package/dest/cmds/deploy_account.d.ts +4 -3
  13. package/dest/cmds/deploy_account.d.ts.map +1 -1
  14. package/dest/cmds/deploy_account.js +27 -16
  15. package/dest/cmds/get_fee_juice_balance.d.ts +5 -0
  16. package/dest/cmds/get_fee_juice_balance.d.ts.map +1 -0
  17. package/dest/cmds/get_fee_juice_balance.js +27 -0
  18. package/dest/cmds/index.d.ts +1 -1
  19. package/dest/cmds/index.d.ts.map +1 -1
  20. package/dest/cmds/index.js +30 -14
  21. package/dest/cmds/send.d.ts +4 -3
  22. package/dest/cmds/send.d.ts.map +1 -1
  23. package/dest/cmds/send.js +27 -23
  24. package/dest/storage/wallet_db.d.ts +6 -1
  25. package/dest/storage/wallet_db.d.ts.map +1 -1
  26. package/dest/storage/wallet_db.js +14 -0
  27. package/dest/utils/options/fees.d.ts +2 -2
  28. package/dest/utils/options/fees.d.ts.map +1 -1
  29. package/dest/utils/options/fees.js +10 -7
  30. package/dest/utils/wallet.d.ts +11 -5
  31. package/dest/utils/wallet.d.ts.map +1 -1
  32. package/dest/utils/wallet.js +73 -49
  33. package/package.json +14 -14
  34. package/src/cmds/check_tx.ts +43 -11
  35. package/src/cmds/create_account.ts +32 -18
  36. package/src/cmds/deploy.ts +24 -15
  37. package/src/cmds/deploy_account.ts +26 -13
  38. package/src/cmds/get_fee_juice_balance.ts +37 -0
  39. package/src/cmds/index.ts +57 -4
  40. package/src/cmds/send.ts +24 -16
  41. package/src/cmds/simulate.ts +1 -1
  42. package/src/storage/wallet_db.ts +14 -0
  43. package/src/utils/options/fees.ts +15 -7
  44. package/src/utils/wallet.ts +84 -69
@@ -1,10 +1,13 @@
1
1
  import { EcdsaRAccountContract, EcdsaRSSHAccountContract } from '@aztec/accounts/ecdsa';
2
2
  import { SchnorrAccountContract } from '@aztec/accounts/schnorr';
3
- import { StubAccountContractArtifact, createStubAccount } from '@aztec/accounts/stub';
3
+ import { StubEcdsaAccountContractArtifact, createStubEcdsaAccount } from '@aztec/accounts/stub/ecdsa';
4
+ import { StubSchnorrAccountContractArtifact, createStubSchnorrAccount } from '@aztec/accounts/stub/schnorr';
4
5
  import { getIdentities } from '@aztec/accounts/utils';
5
- import { SignerlessAccount } from '@aztec/aztec.js/account';
6
+ import { NO_FROM } from '@aztec/aztec.js/account';
6
7
  import { getContractInstanceFromInstantiationParams, getGasLimits } from '@aztec/aztec.js/contracts';
7
8
  import { AccountManager } from '@aztec/aztec.js/wallet';
9
+ import { TxSimulationResultWithAppOffset } from '@aztec/aztec.js/wallet';
10
+ import { DefaultEntrypoint } from '@aztec/entrypoints/default';
8
11
  import { Fr } from '@aztec/foundation/curves/bn254';
9
12
  import { createPXE, getPXEConfig } from '@aztec/pxe/server';
10
13
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
@@ -28,33 +31,39 @@ export class CLIWallet extends BaseWallet {
28
31
  }
29
32
  async getAccounts() {
30
33
  const accounts = await this.db?.listAliases('accounts') ?? [];
31
- return Promise.resolve(accounts.map(({ key, value })=>({
32
- alias: value,
33
- item: AztecAddress.fromString(key)
34
- })));
34
+ return Promise.resolve(accounts.map(({ key, value })=>{
35
+ const alias = key.includes(':') ? key.slice(key.indexOf(':') + 1) : key;
36
+ return {
37
+ alias,
38
+ item: AztecAddress.fromString(value)
39
+ };
40
+ }));
35
41
  }
36
42
  async createCancellationTxExecutionRequest(from, txNonce, increasedFee) {
37
43
  const executionPayload = ExecutionPayload.empty();
38
- const feeOptions = await this.completeFeeOptions(from, executionPayload.feePayer, increasedFee.gasSettings);
44
+ const feeOptions = await this.completeFeeOptions({
45
+ from,
46
+ feePayer: executionPayload.feePayer,
47
+ gasSettings: increasedFee.gasSettings
48
+ });
39
49
  const feeExecutionPayload = await feeOptions.walletFeePaymentMethod?.getExecutionPayload();
40
50
  const fromAccount = await this.getAccountFromAddress(from);
41
51
  const chainInfo = await this.getChainInfo();
42
52
  const executionOptions = {
43
53
  txNonce,
44
54
  cancellable: this.cancellableTransactions,
55
+ // If from is an address, feeOptions include the way the account contract should handle the fee payment
45
56
  feePaymentMethodOptions: feeOptions.accountFeePaymentMethodOptions
46
57
  };
47
58
  return await fromAccount.createTxExecutionRequest(feeExecutionPayload ?? executionPayload, feeOptions.gasSettings, chainInfo, executionOptions);
48
59
  }
49
60
  async proveCancellationTx(from, txNonce, increasedFee) {
50
61
  const cancellationTxRequest = await this.createCancellationTxExecutionRequest(from, txNonce, increasedFee);
51
- return await this.pxe.proveTx(cancellationTxRequest);
62
+ return await this.pxe.proveTx(cancellationTxRequest, this.scopesFrom(from));
52
63
  }
53
64
  async getAccountFromAddress(address) {
54
65
  let account;
55
- if (address.equals(AztecAddress.ZERO)) {
56
- account = new SignerlessAccount();
57
- } else if (this.accountCache.has(address.toString())) {
66
+ if (this.accountCache.has(address.toString())) {
58
67
  return this.accountCache.get(address.toString());
59
68
  } else {
60
69
  const accountManager = await this.createOrRetrieveAccount(address);
@@ -125,66 +134,81 @@ export class CLIWallet extends BaseWallet {
125
134
  * @returns The stub account, contract instance, and artifact for simulation
126
135
  */ async getFakeAccountDataFor(address) {
127
136
  const originalAccount = await this.getAccountFromAddress(address);
128
- // Account contracts can only be overridden if they have an associated address
129
- // Overwriting SignerlessAccount is not supported, and does not really make sense
130
- // since it has no authorization mechanism.
131
- if (originalAccount instanceof SignerlessAccount) {
132
- throw new Error(`Cannot create fake account data for SignerlessAccount at address: ${address}`);
133
- }
134
137
  const originalAddress = originalAccount.getCompleteAddress();
135
138
  const contractInstance = await this.pxe.getContractInstance(originalAddress.address);
136
139
  if (!contractInstance) {
137
140
  throw new Error(`No contract instance found for address: ${originalAddress.address}`);
138
141
  }
139
- const stubAccount = createStubAccount(originalAddress);
140
- const instance = await getContractInstanceFromInstantiationParams(StubAccountContractArtifact, {
142
+ const { type } = await this.db.retrieveAccount(address);
143
+ const isSchnorr = type === 'schnorr';
144
+ const artifact = isSchnorr ? StubSchnorrAccountContractArtifact : StubEcdsaAccountContractArtifact;
145
+ const stubAccount = isSchnorr ? createStubSchnorrAccount(originalAddress) : createStubEcdsaAccount(originalAddress);
146
+ const instance = await getContractInstanceFromInstantiationParams(artifact, {
141
147
  salt: Fr.random()
142
148
  });
143
149
  return {
144
150
  account: stubAccount,
145
151
  instance,
146
- artifact: StubAccountContractArtifact
152
+ artifact
147
153
  };
148
154
  }
149
155
  async simulateTx(executionPayload, opts) {
150
- let simulationResults;
151
- const feeOptions = opts.fee?.estimateGas ? await this.completeFeeOptionsForEstimation(opts.from, executionPayload.feePayer, opts.fee?.gasSettings) : await this.completeFeeOptions(opts.from, executionPayload.feePayer, opts.fee?.gasSettings);
156
+ const simulationResults = await super.simulateTx(executionPayload, opts);
157
+ if (opts.fee?.estimateGas) {
158
+ const feeOptions = await this.completeFeeOptions({
159
+ from: opts.from,
160
+ feePayer: executionPayload.feePayer,
161
+ gasSettings: opts.fee?.gasSettings
162
+ });
163
+ const limits = getGasLimits(simulationResults, opts.fee?.estimatedGasPadding);
164
+ printGasEstimates(feeOptions, limits, this.userLog);
165
+ }
166
+ return simulationResults;
167
+ }
168
+ /**
169
+ * Uses a stub account for kernelless simulation, bypassing real account authorization.
170
+ * Uses DefaultEntrypoint directly for NO_FROM transactions.
171
+ */ async simulateViaEntrypoint(executionPayload, opts) {
172
+ const { from, feeOptions, additionalScopes } = opts;
173
+ const scopes = this.scopesFrom(from, additionalScopes);
152
174
  const feeExecutionPayload = await feeOptions.walletFeePaymentMethod?.getExecutionPayload();
153
- const chainInfo = await this.getChainInfo();
154
- const executionOptions = {
155
- txNonce: Fr.random(),
156
- cancellable: this.cancellableTransactions,
157
- feePaymentMethodOptions: feeOptions.accountFeePaymentMethodOptions
158
- };
159
175
  const finalExecutionPayload = feeExecutionPayload ? mergeExecutionPayloads([
160
176
  feeExecutionPayload,
161
177
  executionPayload
162
178
  ]) : executionPayload;
163
- // Kernelless simulations using the multicall entrypoints are not currently supported,
164
- // since we only override proper account contracts.
165
- // TODO: allow disabling kernels even when no overrides are necessary
166
- if (opts.from.equals(AztecAddress.ZERO)) {
167
- const fromAccount = await this.getAccountFromAddress(opts.from);
168
- const txRequest = await fromAccount.createTxExecutionRequest(finalExecutionPayload, feeOptions.gasSettings, chainInfo, executionOptions);
169
- simulationResults = await this.pxe.simulateTx(txRequest, true, opts?.skipTxValidation, opts?.skipFeeEnforcement ?? true);
179
+ const chainInfo = await this.getChainInfo();
180
+ let overrides;
181
+ let txRequest;
182
+ if (from === NO_FROM) {
183
+ const entrypoint = new DefaultEntrypoint();
184
+ txRequest = await entrypoint.createTxExecutionRequest(finalExecutionPayload, feeOptions.gasSettings, chainInfo);
170
185
  } else {
171
- const { account: fromAccount, instance, artifact } = await this.getFakeAccountDataFor(opts.from);
172
- const txRequest = await fromAccount.createTxExecutionRequest(finalExecutionPayload, feeOptions.gasSettings, chainInfo, executionOptions);
173
- const contractOverrides = {
174
- [opts.from.toString()]: {
175
- instance,
176
- artifact
186
+ const { account, instance, artifact } = await this.getFakeAccountDataFor(from);
187
+ overrides = {
188
+ contracts: {
189
+ [from.toString()]: {
190
+ instance,
191
+ artifact
192
+ }
177
193
  }
178
194
  };
179
- simulationResults = await this.pxe.simulateTx(txRequest, true, true, true, {
180
- contracts: contractOverrides
181
- });
182
- }
183
- if (opts.fee?.estimateGas) {
184
- const limits = getGasLimits(simulationResults, opts.fee?.estimatedGasPadding);
185
- printGasEstimates(feeOptions, limits, this.userLog);
195
+ const executionOptions = {
196
+ txNonce: Fr.random(),
197
+ cancellable: this.cancellableTransactions,
198
+ // If from is an address, feeOptions include the way the account contract should handle the fee payment
199
+ feePaymentMethodOptions: feeOptions.accountFeePaymentMethodOptions
200
+ };
201
+ txRequest = await account.createTxExecutionRequest(finalExecutionPayload, feeOptions.gasSettings, chainInfo, executionOptions);
186
202
  }
187
- return simulationResults;
203
+ const result = await this.pxe.simulateTx(txRequest, {
204
+ simulatePublic: true,
205
+ skipFeeEnforcement: true,
206
+ skipTxValidation: true,
207
+ overrides,
208
+ scopes
209
+ });
210
+ const appCallOffset = await this.computeAppCallOffset(from, feeOptions);
211
+ return TxSimulationResultWithAppOffset.fromResultAndOffset(result, appCallOffset);
188
212
  }
189
213
  // Exposed because of the `aztec-wallet get-tx` command. It has been decided that it's fine to keep around because
190
214
  // this is just a CLI wallet.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/cli-wallet",
3
- "version": "0.0.1-commit.a072138",
3
+ "version": "0.0.1-commit.a89ec08",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/cmds/index.js",
@@ -67,19 +67,19 @@
67
67
  ]
68
68
  },
69
69
  "dependencies": {
70
- "@aztec/accounts": "0.0.1-commit.a072138",
71
- "@aztec/aztec.js": "0.0.1-commit.a072138",
72
- "@aztec/bb.js": "0.0.1-commit.a072138",
73
- "@aztec/cli": "0.0.1-commit.a072138",
74
- "@aztec/entrypoints": "0.0.1-commit.a072138",
75
- "@aztec/ethereum": "0.0.1-commit.a072138",
76
- "@aztec/foundation": "0.0.1-commit.a072138",
77
- "@aztec/kv-store": "0.0.1-commit.a072138",
78
- "@aztec/noir-contracts.js": "0.0.1-commit.a072138",
79
- "@aztec/noir-noirc_abi": "0.0.1-commit.a072138",
80
- "@aztec/pxe": "0.0.1-commit.a072138",
81
- "@aztec/stdlib": "0.0.1-commit.a072138",
82
- "@aztec/wallet-sdk": "0.0.1-commit.a072138",
70
+ "@aztec/accounts": "0.0.1-commit.a89ec08",
71
+ "@aztec/aztec.js": "0.0.1-commit.a89ec08",
72
+ "@aztec/bb.js": "0.0.1-commit.a89ec08",
73
+ "@aztec/cli": "0.0.1-commit.a89ec08",
74
+ "@aztec/entrypoints": "0.0.1-commit.a89ec08",
75
+ "@aztec/ethereum": "0.0.1-commit.a89ec08",
76
+ "@aztec/foundation": "0.0.1-commit.a89ec08",
77
+ "@aztec/kv-store": "0.0.1-commit.a89ec08",
78
+ "@aztec/noir-contracts.js": "0.0.1-commit.a89ec08",
79
+ "@aztec/noir-noirc_abi": "0.0.1-commit.a89ec08",
80
+ "@aztec/pxe": "0.0.1-commit.a89ec08",
81
+ "@aztec/stdlib": "0.0.1-commit.a89ec08",
82
+ "@aztec/wallet-sdk": "0.0.1-commit.a89ec08",
83
83
  "commander": "^12.1.0",
84
84
  "inquirer": "^10.1.8",
85
85
  "source-map-support": "^0.5.21",
@@ -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';
@@ -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,22 +149,49 @@ 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
 
@@ -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,7 +65,7 @@ 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
 
@@ -72,7 +75,7 @@ export async function createAccount(
72
75
  const { paymentMethod, gasSettings } = await feeOpts.toUserFeeOptions(aztecNode, wallet, address);
73
76
 
74
77
  const delegatedDeployment = deployer && !account.address.equals(deployer);
75
- const from = delegatedDeployment ? deployer : AztecAddress.ZERO;
78
+ const from = delegatedDeployment ? deployer : NO_FROM;
76
79
 
77
80
  const deployAccountOpts: DeployAccountOptions = {
78
81
  skipClassPublication: !registerClass,
@@ -82,11 +85,15 @@ export async function createAccount(
82
85
  fee: { paymentMethod, gasSettings },
83
86
  };
84
87
 
88
+ const localStart = performance.now();
85
89
  const deployMethod = await account.getDeployMethod();
86
- const { estimatedGas, stats } = await deployMethod.simulate({
90
+ const sim = await deployMethod.simulate({
87
91
  ...deployAccountOpts,
88
92
  fee: { ...deployAccountOpts.fee, estimateGas: true },
89
93
  });
94
+ // estimateGas: true guarantees these fields are present
95
+ const estimatedGas = sim.estimatedGas!;
96
+ const stats = sim.stats!;
90
97
 
91
98
  if (feeOpts.estimateOnly) {
92
99
  if (json) {
@@ -109,7 +116,7 @@ export async function createAccount(
109
116
  if (!json) {
110
117
  log(`\nWaiting for account contract deployment...`);
111
118
  }
112
- const result = await deployMethod.send({
119
+ const sendOpts = {
113
120
  ...deployAccountOpts,
114
121
  fee: deployAccountOpts.fee
115
122
  ? {
@@ -117,18 +124,25 @@ export async function createAccount(
117
124
  gasSettings: estimatedGas,
118
125
  }
119
126
  : 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;
127
+ };
128
+
129
+ ({ txHash } = await deployMethod.send({ ...sendOpts, wait: NO_WAIT }));
130
+ const localTimeMs = performance.now() - localStart;
131
+
132
+ if (wait) {
133
+ const nodeStart = performance.now();
134
+ txReceipt = await waitForTx(aztecNode, txHash, { timeout: DEFAULT_TX_TIMEOUT_S, waitForStatus });
135
+ const nodeTimeMs = performance.now() - nodeStart;
136
+
126
137
  out.txReceipt = {
127
138
  status: txReceipt.status,
128
139
  transactionFee: txReceipt.transactionFee,
129
140
  };
130
- } else {
131
- txHash = result;
141
+
142
+ if (!json) {
143
+ log(` Local processing time: ${(localTimeMs / 1000).toFixed(1)}s`);
144
+ log(` Node inclusion time: ${(nodeTimeMs / 1000).toFixed(1)}s`);
145
+ }
132
146
  }
133
147
  debugLogger.debug(`Account contract tx sent with hash ${txHash.toString()}`);
134
148
  out.txHash = txHash;
@@ -146,5 +160,5 @@ export async function createAccount(
146
160
  }
147
161
  }
148
162
 
149
- return { alias, address, secretKey, salt };
163
+ return { alias, address, secretKey, salt: instanceSalt };
150
164
  }
@@ -1,13 +1,15 @@
1
+ import { NO_FROM } from '@aztec/aztec.js/account';
1
2
  import { 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,6 +31,7 @@ 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,
@@ -59,11 +62,11 @@ export async function deploy(
59
62
  debugLogger.debug(`Encoded arguments: ${args.join(', ')}`);
60
63
  }
61
64
 
62
- const deploy = contractDeployer.deploy(...args);
65
+ const deployInteraction = contractDeployer.deploy(...args);
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,
69
+ from: deployer ?? NO_FROM,
67
70
  contractAddressSalt: salt,
68
71
  universalDeploy: !deployer,
69
72
  skipClassPublication,
@@ -71,10 +74,14 @@ export async function deploy(
71
74
  skipInstancePublication,
72
75
  };
73
76
 
74
- const { estimatedGas, stats } = await deploy.simulate({
77
+ const localStart = performance.now();
78
+ const sim = await deployInteraction.simulate({
75
79
  ...deployOpts,
76
80
  fee: { ...deployOpts.fee, estimateGas: true },
77
81
  });
82
+ // estimateGas: true guarantees these fields are present
83
+ const estimatedGas = sim.estimatedGas!;
84
+ const stats = sim.stats!;
78
85
 
79
86
  if (feeOpts.estimateOnly) {
80
87
  if (json) {
@@ -94,14 +101,18 @@ export async function deploy(
94
101
  printProfileResult(stats, log);
95
102
  }
96
103
 
97
- const { address, partialAddress } = deploy;
98
- const instance = await deploy.getInstance();
104
+ const { address, partialAddress } = deployInteraction;
105
+ const instance = await deployInteraction.getInstance();
106
+
107
+ const { txHash } = await deployInteraction.send({ ...deployOpts, wait: NO_WAIT });
108
+ const localTimeMs = performance.now() - localStart;
109
+ debugLogger.debug(`Deploy tx sent with hash ${txHash.toString()}`);
110
+ out.hash = txHash;
99
111
 
100
112
  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;
113
+ const nodeStart = performance.now();
114
+ const receipt = await waitForTx(node, txHash, { timeout, waitForStatus });
115
+ const nodeTimeMs = performance.now() - nodeStart;
105
116
 
106
117
  if (!json) {
107
118
  log(`Contract deployed at ${address?.toString()}`);
@@ -111,6 +122,8 @@ export async function deploy(
111
122
  log(`Deployment salt: ${salt.toString()}`);
112
123
  log(`Deployer: ${instance.deployer.toString()}`);
113
124
  log(`Transaction fee: ${receipt.transactionFee?.toString()}`);
125
+ log(` Local processing time: ${(localTimeMs / 1000).toFixed(1)}s`);
126
+ log(` Node inclusion time: ${(nodeTimeMs / 1000).toFixed(1)}s`);
114
127
  } else {
115
128
  out.contract = {
116
129
  address: address?.toString(),
@@ -121,10 +134,6 @@ export async function deploy(
121
134
  };
122
135
  }
123
136
  } 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
137
  if (!json) {
129
138
  log(`Contract deployed at ${address?.toString()}`);
130
139
  log(`Contract partial address ${(await partialAddress)?.toString()}`);
@@ -145,5 +154,5 @@ export async function deploy(
145
154
  if (json) {
146
155
  log(prettyPrintJSON(out));
147
156
  }
148
- return deploy.address;
157
+ return deployInteraction.address;
149
158
  }
@@ -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
71
  fee: { ...deployAccountOpts.fee, estimateGas: true },
69
72
  });
73
+ // estimateGas: true guarantees these fields are present
74
+ const estimatedGas = sim.estimatedGas!;
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;