@aztec/cli-wallet 0.0.1-commit.b655e406 → 0.0.1-commit.b8a057fa

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 (86) hide show
  1. package/README.md +2 -2
  2. package/dest/bin/index.d.ts +2 -1
  3. package/dest/bin/index.js +21 -11
  4. package/dest/cmds/authorize_action.d.ts +2 -2
  5. package/dest/cmds/authorize_action.d.ts.map +1 -1
  6. package/dest/cmds/authorize_action.js +5 -3
  7. package/dest/cmds/bridge_fee_juice.d.ts +2 -2
  8. package/dest/cmds/bridge_fee_juice.d.ts.map +1 -1
  9. package/dest/cmds/bridge_fee_juice.js +3 -2
  10. package/dest/cmds/check_tx.d.ts +1 -1
  11. package/dest/cmds/check_tx.d.ts.map +1 -1
  12. package/dest/cmds/check_tx.js +57 -26
  13. package/dest/cmds/create_account.d.ts +7 -5
  14. package/dest/cmds/create_account.d.ts.map +1 -1
  15. package/dest/cmds/create_account.js +47 -31
  16. package/dest/cmds/create_authwit.d.ts +1 -1
  17. package/dest/cmds/create_authwit.js +1 -1
  18. package/dest/cmds/deploy.d.ts +5 -4
  19. package/dest/cmds/deploy.d.ts.map +1 -1
  20. package/dest/cmds/deploy.js +65 -36
  21. package/dest/cmds/deploy_account.d.ts +4 -3
  22. package/dest/cmds/deploy_account.d.ts.map +1 -1
  23. package/dest/cmds/deploy_account.js +38 -24
  24. package/dest/cmds/get_fee_juice_balance.d.ts +5 -0
  25. package/dest/cmds/get_fee_juice_balance.d.ts.map +1 -0
  26. package/dest/cmds/get_fee_juice_balance.js +27 -0
  27. package/dest/cmds/import_test_accounts.d.ts +1 -1
  28. package/dest/cmds/import_test_accounts.d.ts.map +1 -1
  29. package/dest/cmds/import_test_accounts.js +1 -1
  30. package/dest/cmds/index.d.ts +1 -1
  31. package/dest/cmds/index.d.ts.map +1 -1
  32. package/dest/cmds/index.js +33 -17
  33. package/dest/cmds/profile.d.ts +1 -1
  34. package/dest/cmds/profile.js +1 -1
  35. package/dest/cmds/register_contract.d.ts +1 -1
  36. package/dest/cmds/register_sender.d.ts +1 -1
  37. package/dest/cmds/send.d.ts +5 -4
  38. package/dest/cmds/send.d.ts.map +1 -1
  39. package/dest/cmds/send.js +34 -21
  40. package/dest/cmds/simulate.d.ts +1 -1
  41. package/dest/cmds/simulate.d.ts.map +1 -1
  42. package/dest/cmds/simulate.js +5 -4
  43. package/dest/storage/wallet_db.d.ts +10 -5
  44. package/dest/storage/wallet_db.d.ts.map +1 -1
  45. package/dest/storage/wallet_db.js +61 -32
  46. package/dest/utils/authorizations.d.ts +1 -1
  47. package/dest/utils/cli_wallet_and_node_wrapper.d.ts +1 -1
  48. package/dest/utils/cli_wallet_and_node_wrapper.d.ts.map +1 -1
  49. package/dest/utils/constants.d.ts +4 -0
  50. package/dest/utils/constants.d.ts.map +1 -0
  51. package/dest/utils/constants.js +8 -0
  52. package/dest/utils/ecdsa.d.ts +1 -1
  53. package/dest/utils/options/fees.d.ts +5 -3
  54. package/dest/utils/options/fees.d.ts.map +1 -1
  55. package/dest/utils/options/fees.js +38 -12
  56. package/dest/utils/options/index.d.ts +1 -1
  57. package/dest/utils/options/options.d.ts +1 -1
  58. package/dest/utils/options/options.js +1 -1
  59. package/dest/utils/profiling.d.ts +1 -1
  60. package/dest/utils/profiling.d.ts.map +1 -1
  61. package/dest/utils/profiling.js +9 -1
  62. package/dest/utils/wallet.d.ts +30 -12
  63. package/dest/utils/wallet.d.ts.map +1 -1
  64. package/dest/utils/wallet.js +154 -68
  65. package/package.json +19 -15
  66. package/src/bin/index.ts +19 -13
  67. package/src/cmds/authorize_action.ts +2 -2
  68. package/src/cmds/bridge_fee_juice.ts +3 -2
  69. package/src/cmds/check_tx.ts +65 -34
  70. package/src/cmds/create_account.ts +51 -28
  71. package/src/cmds/create_authwit.ts +1 -1
  72. package/src/cmds/deploy.ts +64 -37
  73. package/src/cmds/deploy_account.ts +39 -20
  74. package/src/cmds/get_fee_juice_balance.ts +37 -0
  75. package/src/cmds/import_test_accounts.ts +5 -1
  76. package/src/cmds/index.ts +63 -9
  77. package/src/cmds/profile.ts +1 -1
  78. package/src/cmds/send.ts +34 -14
  79. package/src/cmds/simulate.ts +6 -8
  80. package/src/storage/wallet_db.ts +65 -38
  81. package/src/utils/cli_wallet_and_node_wrapper.ts +1 -1
  82. package/src/utils/constants.ts +10 -0
  83. package/src/utils/options/fees.ts +46 -13
  84. package/src/utils/options/options.ts +1 -1
  85. package/src/utils/profiling.ts +15 -1
  86. package/src/utils/wallet.ts +170 -79
@@ -1,16 +1,17 @@
1
1
  import type { FeePaymentMethod } from '@aztec/aztec.js/fee';
2
2
  import type { AztecNode } from '@aztec/aztec.js/node';
3
- import type { FeeOptions, Wallet } from '@aztec/aztec.js/wallet';
4
- import { Fr } from '@aztec/foundation/fields';
3
+ import type { Wallet } from '@aztec/aztec.js/wallet';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
5
5
  import type { LogFn } from '@aztec/foundation/log';
6
6
  import type { FieldsOf } from '@aztec/foundation/types';
7
7
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
8
- import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
8
+ import { Gas, GasFees, GasSettings, ManaUsageEstimate } from '@aztec/stdlib/gas';
9
+ import type { FeeOptions } from '@aztec/wallet-sdk/base-wallet';
9
10
 
10
11
  import { Option } from 'commander';
11
12
 
12
13
  import type { WalletDB } from '../../storage/wallet_db.js';
13
- import { BASE_FEE_PADDING } from '../wallet.js';
14
+ import { MIN_FEE_PADDING } from '../constants.js';
14
15
  import { aliasedAddressParser } from './options.js';
15
16
 
16
17
  export type RawCliFeeArgs = {
@@ -114,6 +115,7 @@ export function parsePaymentMethod(
114
115
  payment: string,
115
116
  log: LogFn,
116
117
  db?: WalletDB,
118
+ estimateOnly?: boolean,
117
119
  ): (wallet: Wallet, from: AztecAddress, gasSettings: GasSettings) => Promise<FeePaymentMethod | undefined> {
118
120
  const parsed = payment.split(',').reduce(
119
121
  (acc, item) => {
@@ -135,7 +137,7 @@ export function parsePaymentMethod(
135
137
  if (!parsed.asset) {
136
138
  throw new Error('Missing "asset" in payment option');
137
139
  }
138
- return AztecAddress.fromString(parsed.asset);
140
+ return AztecAddress.fromStringUnsafe(parsed.asset);
139
141
  };
140
142
 
141
143
  return async (wallet: Wallet, from: AztecAddress, gasSettings: GasSettings) => {
@@ -148,7 +150,7 @@ export function parsePaymentMethod(
148
150
  amount: claimAmount,
149
151
  secret: claimSecret,
150
152
  leafIndex: messageLeafIndex,
151
- } = await db.popBridgedFeeJuice(from, log));
153
+ } = estimateOnly ? await db.peekBridgedFeeJuice(from, log) : await db.popBridgedFeeJuice(from, log));
152
154
  } else {
153
155
  ({ claimAmount, claimSecret, messageLeafIndex } = parsed);
154
156
  }
@@ -156,10 +158,10 @@ export function parsePaymentMethod(
156
158
  const { FeeJuicePaymentMethodWithClaim } = await import('@aztec/aztec.js/fee');
157
159
  return new FeeJuicePaymentMethodWithClaim(from, {
158
160
  claimAmount: (typeof claimAmount === 'string'
159
- ? Fr.fromHexString(claimAmount)
161
+ ? Fr.fromString(claimAmount)
160
162
  : new Fr(claimAmount)
161
163
  ).toBigInt(),
162
- claimSecret: Fr.fromHexString(claimSecret),
164
+ claimSecret: typeof claimSecret === 'string' ? Fr.fromString(claimSecret) : claimSecret,
163
165
  messageLeafIndex: BigInt(messageLeafIndex),
164
166
  });
165
167
  } else {
@@ -170,6 +172,9 @@ export function parsePaymentMethod(
170
172
  case 'fpc-public': {
171
173
  const fpc = getFpc();
172
174
  const asset = getAsset();
175
+ log(
176
+ `WARNING: fpc-public is deprecated and will not work on mainnet alpha. Use fee_juice or fpc-sponsored instead.`,
177
+ );
173
178
  log(`Using public fee payment with asset ${asset} via paymaster ${fpc}`);
174
179
  const { PublicFeePaymentMethod } = await import('@aztec/aztec.js/fee');
175
180
  return new PublicFeePaymentMethod(fpc, from, wallet, gasSettings);
@@ -177,6 +182,9 @@ export function parsePaymentMethod(
177
182
  case 'fpc-private': {
178
183
  const fpc = getFpc();
179
184
  const asset = getAsset();
185
+ log(
186
+ `WARNING: fpc-private is deprecated and will not work on mainnet alpha. Use fee_juice or fpc-sponsored instead.`,
187
+ );
180
188
  log(`Using private fee payment with asset ${asset} via paymaster ${fpc}`);
181
189
  const { PrivateFeePaymentMethod } = await import('@aztec/aztec.js/fee');
182
190
  return new PrivateFeePaymentMethod(fpc, from, wallet, gasSettings);
@@ -249,8 +257,11 @@ export class CLIFeeArgs {
249
257
  ) {}
250
258
 
251
259
  async toUserFeeOptions(node: AztecNode, wallet: Wallet, from: AztecAddress): Promise<ParsedFeeOptions> {
252
- const maxFeesPerGas = (await node.getCurrentBaseFees()).mul(1 + BASE_FEE_PADDING);
253
- const gasSettings = GasSettings.default({ ...this.gasSettings, maxFeesPerGas });
260
+ const minFees = await this.getMinFees(node);
261
+ const maxFeesPerGas = minFees.mul(1 + MIN_FEE_PADDING);
262
+ const { txsLimits } = await node.getNodeInfo();
263
+ const gasLimits = this.gasSettings.gasLimits ?? Gas.from(txsLimits.gas);
264
+ const gasSettings = GasSettings.fallback({ ...this.gasSettings, gasLimits, maxFeesPerGas });
254
265
  const paymentMethod = await this.paymentMethod(wallet, from, gasSettings);
255
266
  return {
256
267
  paymentMethod,
@@ -258,10 +269,32 @@ export class CLIFeeArgs {
258
269
  };
259
270
  }
260
271
 
272
+ /**
273
+ * Returns the worst-case min fee across predicted future slots.
274
+ * Falls back to getCurrentMinFees if the node doesn't support getPredictedMinFees.
275
+ */
276
+ private async getMinFees(node: AztecNode): Promise<GasFees> {
277
+ try {
278
+ const predicted = await node.getPredictedMinFees(ManaUsageEstimate.Limit);
279
+ if (predicted.length === 0) {
280
+ return node.getCurrentMinFees();
281
+ }
282
+ return predicted.reduce((worst, fees) => (fees.feePerL2Gas > worst.feePerL2Gas ? fees : worst));
283
+ } catch (err: any) {
284
+ // Fallback for old nodes that don't support getPredictedMinFees.
285
+ // Only fall back on method-not-found errors (JSON-RPC code -32601); rethrow others.
286
+ if (err?.cause?.code === -32601 || err?.message?.includes('Method not found')) {
287
+ return node.getCurrentMinFees();
288
+ }
289
+ throw err;
290
+ }
291
+ }
292
+
261
293
  static parse(args: RawCliFeeArgs, log: LogFn, db?: WalletDB): CLIFeeArgs {
294
+ const estimateOnly = !!args.estimateGasOnly;
262
295
  return new CLIFeeArgs(
263
- !!args.estimateGasOnly,
264
- parsePaymentMethod(args.payment ?? 'method=fee_juice', log, db),
296
+ estimateOnly,
297
+ parsePaymentMethod(args.payment ?? 'method=fee_juice', log, db, estimateOnly),
265
298
  parseGasSettings(args),
266
299
  );
267
300
  }
@@ -287,7 +320,7 @@ function formatGasEstimate(estimate: Pick<GasSettings, 'gasLimits' | 'teardownGa
287
320
  }
288
321
 
289
322
  function getEstimatedCost(estimate: Pick<GasSettings, 'gasLimits' | 'teardownGasLimits'>, maxFeesPerGas: GasFees) {
290
- return GasSettings.default({ ...estimate, maxFeesPerGas })
323
+ return GasSettings.fallback({ ...estimate, maxFeesPerGas })
291
324
  .getFeeLimit()
292
325
  .toBigInt();
293
326
  }
@@ -7,7 +7,7 @@ import { Option } from 'commander';
7
7
  import { readdir, stat } from 'fs/promises';
8
8
 
9
9
  import type { AliasType, WalletDB } from '../../storage/wallet_db.js';
10
- import { AccountTypes } from '../wallet.js';
10
+ import { AccountTypes } from '../constants.js';
11
11
 
12
12
  const TARGET_DIR = 'target';
13
13
 
@@ -95,7 +95,7 @@ export function printProfileResult(
95
95
 
96
96
  if (stats.nodeRPCCalls) {
97
97
  log(format('\nRPC calls:\n'));
98
- for (const [method, { times }] of Object.entries(stats.nodeRPCCalls)) {
98
+ for (const [method, { times }] of Object.entries(stats.nodeRPCCalls.perMethod)) {
99
99
  const calls = times.length;
100
100
  const total = times.reduce((acc, time) => acc + time, 0);
101
101
  const avg = total / calls;
@@ -112,6 +112,20 @@ export function printProfileResult(
112
112
  ),
113
113
  );
114
114
  }
115
+
116
+ const { roundTrips } = stats.nodeRPCCalls;
117
+ log(format('\nRound trips (actual blocking waits):\n'));
118
+ log(format('Round trips:'.padEnd(25), `${roundTrips.roundTrips}`.padStart(COLUMN_MAX_WIDTH)));
119
+ log(
120
+ format(
121
+ 'Total blocking time:'.padEnd(25),
122
+ `${roundTrips.totalBlockingTime.toFixed(2)}ms`.padStart(COLUMN_MAX_WIDTH),
123
+ ),
124
+ );
125
+ if (roundTrips.roundTrips > 0) {
126
+ const avgRoundTrip = roundTrips.totalBlockingTime / roundTrips.roundTrips;
127
+ log(format('Avg round trip:'.padEnd(25), `${avgRoundTrip.toFixed(2)}ms`.padStart(COLUMN_MAX_WIDTH)));
128
+ }
115
129
  }
116
130
 
117
131
  log(format('\nSync time:'.padEnd(25), `${timings.sync?.toFixed(2)}ms`.padStart(16)));
@@ -1,39 +1,46 @@
1
1
  import { EcdsaRAccountContract, EcdsaRSSHAccountContract } from '@aztec/accounts/ecdsa';
2
- import { SchnorrAccountContract } from '@aztec/accounts/schnorr';
3
- import { StubAccountContractArtifact, createStubAccount } from '@aztec/accounts/stub';
2
+ import { StubEcdsaAccountContractArtifact, createStubEcdsaAccount } from '@aztec/accounts/ecdsa/stub';
3
+ import { SchnorrAccountContract, SchnorrInitializerlessAccountContract } from '@aztec/accounts/schnorr';
4
+ import { StubSchnorrAccountContractArtifact, createStubSchnorrAccount } from '@aztec/accounts/schnorr/stub';
4
5
  import { getIdentities } from '@aztec/accounts/utils';
5
- import { type Account, type AccountContract, SignerlessAccount } from '@aztec/aztec.js/account';
6
+ import { type Account, type AccountContract, NO_FROM } from '@aztec/aztec.js/account';
6
7
  import {
8
+ ContractFunctionInteraction,
7
9
  type InteractionFeeOptions,
8
- getContractInstanceFromInstantiationParams,
9
- getGasLimits,
10
+ getContractClassFromArtifact,
10
11
  } from '@aztec/aztec.js/contracts';
11
12
  import type { AztecNode } from '@aztec/aztec.js/node';
12
- import { UniqueNote } from '@aztec/aztec.js/note';
13
- import { AccountManager, type Aliased, BaseWallet, type SimulateOptions } from '@aztec/aztec.js/wallet';
13
+ import { AccountManager, type Aliased } from '@aztec/aztec.js/wallet';
14
+ import { TxSimulationResultWithAppOffset } from '@aztec/aztec.js/wallet';
14
15
  import type { DefaultAccountEntrypointOptions } from '@aztec/entrypoints/account';
15
- import { ExecutionPayload, mergeExecutionPayloads } from '@aztec/entrypoints/payload';
16
- import { Fr } from '@aztec/foundation/fields';
16
+ import { DefaultEntrypoint } from '@aztec/entrypoints/default';
17
+ import { Fr } from '@aztec/foundation/curves/bn254';
17
18
  import type { LogFn } from '@aztec/foundation/log';
19
+ import type { NotesFilter } from '@aztec/pxe/client/lazy';
18
20
  import type { PXEConfig } from '@aztec/pxe/config';
19
21
  import type { PXE } from '@aztec/pxe/server';
20
22
  import { createPXE, getPXEConfig } from '@aztec/pxe/server';
23
+ import { getStandardAuthRegistry } from '@aztec/standard-contracts/auth-registry';
21
24
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
25
+ import type { Gas, GasUsed } from '@aztec/stdlib/gas';
22
26
  import { deriveSigningKey } from '@aztec/stdlib/keys';
23
- import type { NotesFilter } from '@aztec/stdlib/note';
24
- import type { TxProvingResult, TxSimulationResult } from '@aztec/stdlib/tx';
27
+ import { NoteDao } from '@aztec/stdlib/note';
28
+ import type { SimulationOverrides, TxExecutionRequest, TxProvingResult } from '@aztec/stdlib/tx';
29
+ import { ExecutionPayload, mergeExecutionPayloads } from '@aztec/stdlib/tx';
30
+ import { BaseWallet, type SimulateViaEntrypointOptions, getGasLimits } from '@aztec/wallet-sdk/base-wallet';
25
31
 
26
32
  import type { WalletDB } from '../storage/wallet_db.js';
33
+ import type { AccountType } from './constants.js';
27
34
  import { extractECDSAPublicKeyFromBase64String } from './ecdsa.js';
28
- import { printGasEstimates } from './options/fees.js';
29
35
 
30
- export const AccountTypes = ['schnorr', 'ecdsasecp256r1', 'ecdsasecp256r1ssh', 'ecdsasecp256k1'] as const;
31
- export type AccountType = (typeof AccountTypes)[number];
32
-
33
- export const BASE_FEE_PADDING = 0.5;
36
+ /** Padding the CLI wallet applies to simulated gas usage when deriving declared gas limits. */
37
+ const DEFAULT_ESTIMATED_GAS_PADDING = 0.1;
34
38
 
35
39
  export class CLIWallet extends BaseWallet {
36
40
  private accountCache = new Map<string, Account>();
41
+ // Stub class ids, populated on wallet startup
42
+ // to avoid redundant work per simulation
43
+ private stubClassIds = new Map<AccountType, Fr>();
37
44
 
38
45
  constructor(
39
46
  pxe: PXE,
@@ -53,12 +60,55 @@ export class CLIWallet extends BaseWallet {
53
60
  ): Promise<CLIWallet> {
54
61
  const pxeConfig = Object.assign(getPXEConfig(), overridePXEConfig);
55
62
  const pxe = await createPXE(node, pxeConfig);
56
- return new CLIWallet(pxe, node, log, db);
63
+ const wallet = new CLIWallet(pxe, node, log, db);
64
+ await wallet.initStubClasses();
65
+ await wallet.registerAuthRegistry();
66
+ return wallet;
67
+ }
68
+
69
+ private async registerAuthRegistry(): Promise<void> {
70
+ const { instance, artifact } = await getStandardAuthRegistry();
71
+ await this.pxe.registerContractClass(artifact);
72
+ await this.pxe.registerContract(instance);
73
+ }
74
+
75
+ /**
76
+ * Hashes and registers the stub class for every supported account type with PXE, populating
77
+ * stubClassIds. Called on wallet initialization.
78
+ */
79
+ private async initStubClasses(): Promise<void> {
80
+ const { id: schnorrClassId } = await getContractClassFromArtifact(StubSchnorrAccountContractArtifact);
81
+ await this.pxe.registerContractClass(StubSchnorrAccountContractArtifact);
82
+
83
+ // ecdsa stubs share the same class id
84
+ const { id: ecdsaClassId } = await getContractClassFromArtifact(StubEcdsaAccountContractArtifact);
85
+ await this.pxe.registerContractClass(StubEcdsaAccountContractArtifact);
86
+
87
+ this.stubClassIds.set('schnorr', schnorrClassId);
88
+ this.stubClassIds.set('schnorr_initializerless', schnorrClassId);
89
+ this.stubClassIds.set('ecdsasecp256k1', ecdsaClassId);
90
+ this.stubClassIds.set('ecdsasecp256r1', ecdsaClassId);
91
+ this.stubClassIds.set('ecdsasecp256r1ssh', ecdsaClassId);
57
92
  }
58
93
 
59
94
  override async getAccounts(): Promise<Aliased<AztecAddress>[]> {
60
95
  const accounts = (await this.db?.listAliases('accounts')) ?? [];
61
- return Promise.resolve(accounts.map(({ key, value }) => ({ alias: value, item: AztecAddress.fromString(key) })));
96
+ return Promise.resolve(
97
+ accounts.map(({ key, value }) => {
98
+ const alias = key.includes(':') ? key.slice(key.indexOf(':') + 1) : key;
99
+ return { alias, item: AztecAddress.fromStringUnsafe(value) };
100
+ }),
101
+ );
102
+ }
103
+
104
+ /**
105
+ * Derives suggested total and teardown gas limits from simulated gas usage, padded and clamped to the
106
+ * network's per-tx admission limits.
107
+ * @param gasUsed - The gas consumed during simulation (from a `simulate({ includeMetadata: true })` result).
108
+ */
109
+ async estimateGasLimits(gasUsed: GasUsed): Promise<{ gasLimits: Gas; teardownGasLimits: Gas }> {
110
+ const maxTxGasLimits = await this.getMaxTxGasLimits();
111
+ return getGasLimits(gasUsed, maxTxGasLimits, DEFAULT_ESTIMATED_GAS_PADDING);
62
112
  }
63
113
 
64
114
  private async createCancellationTxExecutionRequest(
@@ -66,17 +116,25 @@ export class CLIWallet extends BaseWallet {
66
116
  txNonce: Fr,
67
117
  increasedFee: InteractionFeeOptions,
68
118
  ) {
69
- const feeOptions = await this.getDefaultFeeOptions(from, increasedFee);
119
+ const executionPayload = ExecutionPayload.empty();
120
+ const feeOptions = await this.completeFeeOptions({
121
+ from,
122
+ feePayer: executionPayload.feePayer,
123
+ gasSettings: increasedFee.gasSettings,
124
+ });
70
125
  const feeExecutionPayload = await feeOptions.walletFeePaymentMethod?.getExecutionPayload();
71
126
  const fromAccount = await this.getAccountFromAddress(from);
127
+ const chainInfo = await this.getChainInfo();
72
128
  const executionOptions: DefaultAccountEntrypointOptions = {
73
129
  txNonce,
74
130
  cancellable: this.cancellableTransactions,
75
- feePaymentMethodOptions: feeOptions.accountFeePaymentMethodOptions,
131
+ // If from is an address, feeOptions include the way the account contract should handle the fee payment
132
+ feePaymentMethodOptions: feeOptions.accountFeePaymentMethodOptions!,
76
133
  };
77
134
  return await fromAccount.createTxExecutionRequest(
78
- feeExecutionPayload ?? ExecutionPayload.empty(),
135
+ feeExecutionPayload ?? executionPayload,
79
136
  feeOptions.gasSettings,
137
+ chainInfo,
80
138
  executionOptions,
81
139
  );
82
140
  }
@@ -87,15 +145,12 @@ export class CLIWallet extends BaseWallet {
87
145
  increasedFee: InteractionFeeOptions,
88
146
  ): Promise<TxProvingResult> {
89
147
  const cancellationTxRequest = await this.createCancellationTxExecutionRequest(from, txNonce, increasedFee);
90
- return await this.pxe.proveTx(cancellationTxRequest);
148
+ return await this.pxe.proveTx(cancellationTxRequest, { scopes: this.scopesFrom(from), senderForTags: from });
91
149
  }
92
150
 
93
151
  override async getAccountFromAddress(address: AztecAddress) {
94
152
  let account: Account | undefined;
95
- if (address.equals(AztecAddress.ZERO)) {
96
- const chainInfo = await this.getChainInfo();
97
- account = new SignerlessAccount(chainInfo);
98
- } else if (this.accountCache.has(address.toString())) {
153
+ if (this.accountCache.has(address.toString())) {
99
154
  return this.accountCache.get(address.toString())!;
100
155
  } else {
101
156
  const accountManager = await this.createOrRetrieveAccount(address);
@@ -109,13 +164,27 @@ export class CLIWallet extends BaseWallet {
109
164
  }
110
165
 
111
166
  private async createAccount(secret: Fr, salt: Fr, contract: AccountContract): Promise<AccountManager> {
112
- const accountManager = await AccountManager.create(this, secret, contract, salt);
167
+ const accountManager = await AccountManager.create(this, secret, contract, { salt });
113
168
 
114
169
  const instance = accountManager.getInstance();
115
170
  const artifact = await contract.getContractArtifact();
116
171
 
117
172
  await this.registerContract(instance, artifact, secret);
118
173
  this.accountCache.set(accountManager.address.toString(), await accountManager.getAccount());
174
+
175
+ // Initializerless accounts have no deployment tx; their address commits to the signing public key
176
+ // (via the contract's immutablesHash, resolved by AccountManager.create) and the constructor's
177
+ // storage writes are materialized locally via a simulated "store" call here.
178
+ if (contract instanceof SchnorrInitializerlessAccountContract) {
179
+ const constructorAbi = artifact.functions.find(f => f.name === 'constructor');
180
+ if (!constructorAbi) {
181
+ throw new Error('Could not create SchnorrInitializerlessAccount: constructor ABI not found');
182
+ }
183
+ const { x, y } = await contract.getSigningPublicKey();
184
+ const storeCall = new ContractFunctionInteraction(this, instance.address, constructorAbi, [x, y]);
185
+ await storeCall.simulate({ from: instance.address });
186
+ }
187
+
119
188
  return accountManager;
120
189
  }
121
190
 
@@ -143,6 +212,14 @@ export class CLIWallet extends BaseWallet {
143
212
  account = await this.createAccount(secretKey, salt, new SchnorrAccountContract(deriveSigningKey(secretKey)));
144
213
  break;
145
214
  }
215
+ case 'schnorr_initializerless': {
216
+ account = await this.createAccount(
217
+ secretKey,
218
+ salt,
219
+ new SchnorrInitializerlessAccountContract(deriveSigningKey(secretKey)),
220
+ );
221
+ break;
222
+ }
146
223
  case 'ecdsasecp256r1': {
147
224
  account = await this.createAccount(
148
225
  secretKey,
@@ -178,76 +255,84 @@ export class CLIWallet extends BaseWallet {
178
255
  return account;
179
256
  }
180
257
 
258
+ /**
259
+ * Creates a stub account that impersonates the given address, allowing kernelless simulations
260
+ * to bypass the account's authorization mechanisms via contract overrides.
261
+ * @param address - The address of the account to impersonate
262
+ * @returns The stub account, contract instance, and artifact for simulation
263
+ */
181
264
  private async getFakeAccountDataFor(address: AztecAddress) {
182
- const chainInfo = await this.getChainInfo();
183
265
  const originalAccount = await this.getAccountFromAddress(address);
184
266
  const originalAddress = originalAccount.getCompleteAddress();
185
- const { contractInstance } = await this.pxe.getContractMetadata(originalAddress.address);
267
+ const contractInstance = await this.pxe.getContractInstance(originalAddress.address);
186
268
  if (!contractInstance) {
187
269
  throw new Error(`No contract instance found for address: ${originalAddress.address}`);
188
270
  }
189
- const stubAccount = createStubAccount(originalAddress, chainInfo);
190
- const instance = await getContractInstanceFromInstantiationParams(StubAccountContractArtifact, {
191
- salt: Fr.random(),
192
- });
193
- return {
194
- account: stubAccount,
195
- instance,
196
- artifact: StubAccountContractArtifact,
197
- };
271
+ const { type } = await this.db!.retrieveAccount(address);
272
+ const stubAccount =
273
+ type === 'schnorr' || type === 'schnorr_initializerless'
274
+ ? createStubSchnorrAccount(originalAddress)
275
+ : createStubEcdsaAccount(originalAddress);
276
+ const stubClassId = this.stubClassIds.get(type);
277
+ if (!stubClassId) {
278
+ throw new Error(
279
+ `Stub class for account type '${type}' was not registered at wallet init. This is a bug — initStubClasses should cover every supported AccountType.`,
280
+ );
281
+ }
282
+ const instance = { ...contractInstance, currentContractClassId: stubClassId };
283
+ return { account: stubAccount, instance };
198
284
  }
199
285
 
200
- override async simulateTx(executionPayload: ExecutionPayload, opts: SimulateOptions): Promise<TxSimulationResult> {
201
- let simulationResults;
202
- const feeOptions = opts.fee?.estimateGas
203
- ? await this.getFeeOptionsForGasEstimation(opts.from, opts.fee)
204
- : await this.getDefaultFeeOptions(opts.from, opts.fee);
286
+ /**
287
+ * Uses a stub account for kernelless simulation, bypassing real account authorization.
288
+ * Uses DefaultEntrypoint directly for NO_FROM transactions.
289
+ */
290
+ protected override async simulateViaEntrypoint(
291
+ executionPayload: ExecutionPayload,
292
+ opts: SimulateViaEntrypointOptions,
293
+ ): Promise<TxSimulationResultWithAppOffset> {
294
+ const { from, feeOptions, additionalScopes, sendMessagesAs } = opts;
295
+ const scopes = this.scopesFrom(from, additionalScopes);
205
296
  const feeExecutionPayload = await feeOptions.walletFeePaymentMethod?.getExecutionPayload();
206
- const executionOptions: DefaultAccountEntrypointOptions = {
207
- txNonce: Fr.random(),
208
- cancellable: this.cancellableTransactions,
209
- feePaymentMethodOptions: feeOptions.accountFeePaymentMethodOptions,
210
- };
211
297
  const finalExecutionPayload = feeExecutionPayload
212
298
  ? mergeExecutionPayloads([feeExecutionPayload, executionPayload])
213
299
  : executionPayload;
300
+ const chainInfo = await this.getChainInfo();
214
301
 
215
- // Kernelless simulations using the multicall entrypoints are not currently supported,
216
- // since we only override proper account contracts.
217
- // TODO: allow disabling kernels even when no overrides are necessary
218
- if (opts.from.equals(AztecAddress.ZERO)) {
219
- const fromAccount = await this.getAccountFromAddress(opts.from);
220
- const txRequest = await fromAccount.createTxExecutionRequest(
221
- finalExecutionPayload,
222
- feeOptions.gasSettings,
223
- executionOptions,
224
- );
225
- simulationResults = await this.pxe.simulateTx(
226
- txRequest,
227
- true /* simulatePublic */,
228
- opts?.skipTxValidation,
229
- opts?.skipFeeEnforcement ?? true,
230
- );
302
+ let overrides: SimulationOverrides | undefined;
303
+ let txRequest: TxExecutionRequest;
304
+ if (from === NO_FROM) {
305
+ const entrypoint = new DefaultEntrypoint();
306
+ txRequest = await entrypoint.createTxExecutionRequest(finalExecutionPayload, feeOptions.gasSettings, chainInfo);
231
307
  } else {
232
- const { account: fromAccount, instance, artifact } = await this.getFakeAccountDataFor(opts.from);
233
- const txRequest = await fromAccount.createTxExecutionRequest(
308
+ const { account, instance } = await this.getFakeAccountDataFor(from);
309
+ overrides = {
310
+ contracts: { [from.toString()]: { instance } },
311
+ };
312
+ const executionOptions: DefaultAccountEntrypointOptions = {
313
+ txNonce: Fr.random(),
314
+ cancellable: this.cancellableTransactions,
315
+ // If from is an address, feeOptions include the way the account contract should handle the fee payment
316
+ feePaymentMethodOptions: feeOptions.accountFeePaymentMethodOptions!,
317
+ };
318
+ txRequest = await account.createTxExecutionRequest(
234
319
  finalExecutionPayload,
235
320
  feeOptions.gasSettings,
321
+ chainInfo,
236
322
  executionOptions,
237
323
  );
238
- const contractOverrides = {
239
- [opts.from.toString()]: { instance, artifact },
240
- };
241
- simulationResults = await this.pxe.simulateTx(txRequest, true /* simulatePublic */, true, true, {
242
- contracts: contractOverrides,
243
- });
244
324
  }
245
325
 
246
- if (opts.fee?.estimateGas) {
247
- const limits = getGasLimits(simulationResults, opts.fee?.estimatedGasPadding);
248
- printGasEstimates(feeOptions, limits, this.userLog);
249
- }
250
- return simulationResults;
326
+ const result = await this.pxe.simulateTx(txRequest, {
327
+ simulatePublic: true,
328
+ skipFeeEnforcement: true,
329
+ skipTxValidation: true,
330
+ overrides,
331
+ scopes,
332
+ senderForTags: this.senderForTagsFrom(from, sendMessagesAs),
333
+ });
334
+ const appCallOffset = await this.computeAppCallOffset(from, feeOptions);
335
+ return TxSimulationResultWithAppOffset.fromResultAndOffset(result, appCallOffset);
251
336
  }
252
337
 
253
338
  // Exposed because of the `aztec-wallet get-tx` command. It has been decided that it's fine to keep around because
@@ -258,7 +343,13 @@ export class CLIWallet extends BaseWallet {
258
343
 
259
344
  // Exposed because of the `aztec-wallet get-tx` command. It has been decided that it's fine to keep around because
260
345
  // this is just a CLI wallet.
261
- getNotes(filter: NotesFilter): Promise<UniqueNote[]> {
262
- return this.pxe.getNotes(filter);
346
+ getNotes(filter: NotesFilter): Promise<NoteDao[]> {
347
+ return this.pxe.debug.getNotes(filter);
348
+ }
349
+
350
+ // Exposed because of the `aztec-wallet get-tx` command. It has been decided that it's fine to keep around because
351
+ // this is just a CLI wallet.
352
+ getContractArtifact(id: Fr) {
353
+ return this.pxe.getContractArtifact(id);
263
354
  }
264
355
  }