@aztec/cli-wallet 0.0.1-commit.c2eed6949 → 0.0.1-commit.c52d6e7

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 (51) hide show
  1. package/dest/bin/index.js +1 -1
  2. package/dest/cmds/check_tx.js +15 -13
  3. package/dest/cmds/create_account.d.ts +4 -2
  4. package/dest/cmds/create_account.d.ts.map +1 -1
  5. package/dest/cmds/create_account.js +26 -10
  6. package/dest/cmds/deploy.d.ts +3 -3
  7. package/dest/cmds/deploy.d.ts.map +1 -1
  8. package/dest/cmds/deploy.js +23 -21
  9. package/dest/cmds/deploy_account.js +4 -7
  10. package/dest/cmds/import_test_accounts.d.ts +1 -1
  11. package/dest/cmds/import_test_accounts.d.ts.map +1 -1
  12. package/dest/cmds/import_test_accounts.js +2 -1
  13. package/dest/cmds/index.d.ts +1 -1
  14. package/dest/cmds/index.d.ts.map +1 -1
  15. package/dest/cmds/index.js +10 -9
  16. package/dest/cmds/send.js +3 -6
  17. package/dest/cmds/simulate.d.ts +1 -1
  18. package/dest/cmds/simulate.d.ts.map +1 -1
  19. package/dest/cmds/simulate.js +2 -1
  20. package/dest/storage/wallet_db.d.ts +12 -4
  21. package/dest/storage/wallet_db.d.ts.map +1 -1
  22. package/dest/storage/wallet_db.js +29 -1
  23. package/dest/utils/authorizations.js +2 -2
  24. package/dest/utils/constants.d.ts +2 -2
  25. package/dest/utils/constants.d.ts.map +1 -1
  26. package/dest/utils/constants.js +1 -0
  27. package/dest/utils/options/fees.d.ts +3 -2
  28. package/dest/utils/options/fees.d.ts.map +1 -1
  29. package/dest/utils/options/fees.js +34 -10
  30. package/dest/utils/options/options.d.ts +2 -2
  31. package/dest/utils/options/options.d.ts.map +1 -1
  32. package/dest/utils/options/options.js +5 -5
  33. package/dest/utils/wallet.d.ts +31 -7
  34. package/dest/utils/wallet.d.ts.map +1 -1
  35. package/dest/utils/wallet.js +148 -72
  36. package/package.json +16 -15
  37. package/src/bin/index.ts +1 -1
  38. package/src/cmds/check_tx.ts +17 -15
  39. package/src/cmds/create_account.ts +27 -15
  40. package/src/cmds/deploy.ts +22 -23
  41. package/src/cmds/deploy_account.ts +4 -4
  42. package/src/cmds/import_test_accounts.ts +12 -1
  43. package/src/cmds/index.ts +14 -11
  44. package/src/cmds/send.ts +3 -3
  45. package/src/cmds/simulate.ts +2 -1
  46. package/src/storage/wallet_db.ts +38 -2
  47. package/src/utils/authorizations.ts +3 -3
  48. package/src/utils/constants.ts +7 -1
  49. package/src/utils/options/fees.ts +36 -10
  50. package/src/utils/options/options.ts +5 -5
  51. package/src/utils/wallet.ts +188 -91
@@ -1,5 +1,5 @@
1
1
  import { NO_FROM } from '@aztec/aztec.js/account';
2
- import { AztecAddress } from '@aztec/aztec.js/addresses';
2
+ import type { AztecAddress } from '@aztec/aztec.js/addresses';
3
3
  import type { DeployOptions } from '@aztec/aztec.js/contracts';
4
4
  import { NO_WAIT } from '@aztec/aztec.js/contracts';
5
5
  import { ContractDeployer } from '@aztec/aztec.js/deployment';
@@ -36,6 +36,7 @@ export async function deploy(
36
36
  timeout: number = DEFAULT_TX_TIMEOUT_S,
37
37
  debugLogger: Logger,
38
38
  log: LogFn,
39
+ universal?: boolean,
39
40
  ) {
40
41
  const out: Record<string, any> = {};
41
42
  salt ??= Fr.random();
@@ -45,12 +46,7 @@ export async function deploy(
45
46
 
46
47
  // TODO(#12081): Add contractArtifact.noirVersion and check here (via Noir.lock)?
47
48
 
48
- const contractDeployer = new ContractDeployer(
49
- contractArtifact,
50
- wallet,
51
- publicKeys ?? PublicKeys.default(),
52
- initializer,
53
- );
49
+ const contractDeployer = new ContractDeployer(contractArtifact, wallet, initializer);
54
50
 
55
51
  let args = [];
56
52
  if (rawArgs.length > 0) {
@@ -62,13 +58,15 @@ export async function deploy(
62
58
  debugLogger.debug(`Encoded arguments: ${args.join(', ')}`);
63
59
  }
64
60
 
65
- const deployInteraction = contractDeployer.deploy(...args);
61
+ const deployInteraction = contractDeployer.deploy(args, {
62
+ salt,
63
+ publicKeys: publicKeys ?? PublicKeys.default(),
64
+ ...(universal ? { universalDeploy: true as const } : {}),
65
+ });
66
66
  const { paymentMethod, gasSettings } = await feeOpts.toUserFeeOptions(node, wallet, deployer);
67
67
  const deployOpts: DeployOptions = {
68
68
  fee: { gasSettings, paymentMethod },
69
69
  from: deployer ?? NO_FROM,
70
- contractAddressSalt: salt,
71
- universalDeploy: !deployer,
72
70
  skipClassPublication,
73
71
  skipInitialization,
74
72
  skipInstancePublication,
@@ -77,10 +75,10 @@ export async function deploy(
77
75
  const localStart = performance.now();
78
76
  const sim = await deployInteraction.simulate({
79
77
  ...deployOpts,
80
- fee: { ...deployOpts.fee, estimateGas: true },
78
+ includeMetadata: true,
81
79
  });
82
- // estimateGas: true guarantees these fields are present
83
- const estimatedGas = sim.estimatedGas!;
80
+ // includeMetadata: true guarantees these fields are present
81
+ const estimatedGas = await wallet.estimateGasLimits(sim.gasUsed!);
84
82
  const stats = sim.stats!;
85
83
 
86
84
  if (feeOpts.estimateOnly) {
@@ -101,8 +99,9 @@ export async function deploy(
101
99
  printProfileResult(stats, log);
102
100
  }
103
101
 
104
- const { address, partialAddress } = deployInteraction;
105
102
  const instance = await deployInteraction.getInstance();
103
+ const address = instance.address;
104
+ const partialAddress = await deployInteraction.getPartialAddress();
106
105
 
107
106
  const { txHash } = await deployInteraction.send({ ...deployOpts, wait: NO_WAIT });
108
107
  const localTimeMs = performance.now() - localStart;
@@ -115,8 +114,8 @@ export async function deploy(
115
114
  const nodeTimeMs = performance.now() - nodeStart;
116
115
 
117
116
  if (!json) {
118
- log(`Contract deployed at ${address?.toString()}`);
119
- log(`Contract partial address ${(await partialAddress)?.toString()}`);
117
+ log(`Contract deployed at ${address.toString()}`);
118
+ log(`Contract partial address ${partialAddress.toString()}`);
120
119
  log(`Contract init hash ${instance.initializationHash.toString()}`);
121
120
  log(`Deployment tx hash: ${txHash.toString()}`);
122
121
  log(`Deployment salt: ${salt.toString()}`);
@@ -126,8 +125,8 @@ export async function deploy(
126
125
  log(` Node inclusion time: ${(nodeTimeMs / 1000).toFixed(1)}s`);
127
126
  } else {
128
127
  out.contract = {
129
- address: address?.toString(),
130
- partialAddress: (await partialAddress)?.toString(),
128
+ address: address.toString(),
129
+ partialAddress: partialAddress.toString(),
131
130
  initializationHash: instance.initializationHash.toString(),
132
131
  salt: salt.toString(),
133
132
  transactionFee: receipt.transactionFee?.toString(),
@@ -135,16 +134,16 @@ export async function deploy(
135
134
  }
136
135
  } else {
137
136
  if (!json) {
138
- log(`Contract deployed at ${address?.toString()}`);
139
- log(`Contract partial address ${(await partialAddress)?.toString()}`);
137
+ log(`Contract deployed at ${address.toString()}`);
138
+ log(`Contract partial address ${partialAddress.toString()}`);
140
139
  log(`Contract init hash ${instance.initializationHash.toString()}`);
141
140
  log(`Deployment tx hash: ${txHash.toString()}`);
142
141
  log(`Deployment salt: ${salt.toString()}`);
143
142
  log(`Deployer: ${instance.deployer.toString()}`);
144
143
  } else {
145
144
  out.contract = {
146
- address: address?.toString(),
147
- partialAddress: (await partialAddress)?.toString(),
145
+ address: address.toString(),
146
+ partialAddress: partialAddress.toString(),
148
147
  initializationHash: instance.initializationHash.toString(),
149
148
  salt: salt.toString(),
150
149
  };
@@ -154,5 +153,5 @@ export async function deploy(
154
153
  if (json) {
155
154
  log(prettyPrintJSON(out));
156
155
  }
157
- return deployInteraction.address;
156
+ return await deployInteraction.getAddress();
158
157
  }
@@ -30,7 +30,7 @@ export async function deployAccount(
30
30
  ) {
31
31
  const out: Record<string, any> = {};
32
32
 
33
- const account = await wallet.createOrRetrieveAccount(address);
33
+ const account = await wallet.retrieveAccount(address);
34
34
  const { partialAddress, publicKeys } = await account.getCompleteAddress();
35
35
  const { initializationHash, salt } = account.getInstance();
36
36
 
@@ -68,10 +68,10 @@ export async function deployAccount(
68
68
  const deployMethod = await account.getDeployMethod();
69
69
  const sim = await deployMethod.simulate({
70
70
  ...deployAccountOpts,
71
- fee: { ...deployAccountOpts.fee, estimateGas: true },
71
+ includeMetadata: true,
72
72
  });
73
- // estimateGas: true guarantees these fields are present
74
- const estimatedGas = sim.estimatedGas!;
73
+ // includeMetadata: true guarantees these fields are present
74
+ const estimatedGas = await wallet.estimateGasLimits(sim.gasUsed!);
75
75
  const stats = sim.stats!;
76
76
 
77
77
  if (feeOpts.estimateOnly) {
@@ -16,7 +16,18 @@ 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
+ {
22
+ type: 'schnorr_initializerless',
23
+ signingKey: account.signingKey,
24
+ secretKey: secret,
25
+ salt,
26
+ alias,
27
+ publicKey: undefined,
28
+ },
29
+ log,
30
+ );
20
31
 
21
32
  if (json) {
22
33
  out[alias] = {
package/src/cmds/index.ts CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  ETHEREUM_HOSTS,
5
5
  PRIVATE_KEY,
6
6
  addOptions,
7
- createSecretKeyOption,
7
+ createSigningKeyOption,
8
8
  l1ChainIdOption,
9
9
  parseBigint,
10
10
  parseFieldFromHexString,
@@ -24,7 +24,7 @@ import {
24
24
  ARTIFACT_DESCRIPTION,
25
25
  CLIFeeArgs,
26
26
  aliasedAddressParser,
27
- aliasedSecretKeyParser,
27
+ aliasedSigningKeyParser,
28
28
  aliasedTxHashParser,
29
29
  artifactPathFromPromiseOrAlias,
30
30
  artifactPathParser,
@@ -96,8 +96,8 @@ export function injectCommands(
96
96
  'Public key that identifies a private signing key stored outside of the wallet. Used for ECDSA SSH accounts over the secp256r1 curve.',
97
97
  )
98
98
  .addOption(
99
- createSecretKeyOption('Secret key for account. Uses random by default.', false, sk =>
100
- aliasedSecretKeyParser(sk, db),
99
+ createSigningKeyOption('Signing key for account. Uses random by default.', false, sk =>
100
+ aliasedSigningKeyParser(sk, db),
101
101
  ).conflicts('public-key'),
102
102
  )
103
103
  .addOption(createAliasOption('Alias for the account. Used for easy reference in subsequent commands.', !db))
@@ -124,7 +124,7 @@ export function injectCommands(
124
124
  const {
125
125
  type,
126
126
  from: parsedFromAddress,
127
- secretKey,
127
+ signingKey,
128
128
  salt,
129
129
  wait,
130
130
  waitForStatus: waitForStatusStr,
@@ -156,7 +156,7 @@ export function injectCommands(
156
156
  wallet,
157
157
  node,
158
158
  type,
159
- secretKey,
159
+ signingKey,
160
160
  salt,
161
161
  publicKey,
162
162
  alias,
@@ -174,8 +174,8 @@ export function injectCommands(
174
174
  log,
175
175
  );
176
176
  if (db) {
177
- const { address, alias, secretKey, salt } = accountCreationResult;
178
- await db.storeAccount(address, { type, secretKey, salt, alias, publicKey }, log);
177
+ const { address, alias, signingKey, secretKey, salt } = accountCreationResult;
178
+ await db.storeAccount(address, { type, signingKey, secretKey, salt, alias, publicKey }, log);
179
179
  }
180
180
  });
181
181
 
@@ -297,12 +297,12 @@ export function injectCommands(
297
297
  const { wallet, node } = walletAndNodeWrapper;
298
298
  const artifactPath = await artifactPathPromise;
299
299
 
300
- debugLogger.info(`Using wallet with address ${parsedFromAddress.toString()}`);
300
+ debugLogger.info(`Using wallet with address ${parsedFromAddress?.toString() ?? '<none>'}`);
301
301
 
302
302
  const address = await deploy(
303
303
  wallet,
304
304
  node,
305
- universal ? undefined : parsedFromAddress,
305
+ parsedFromAddress,
306
306
  artifactPath,
307
307
  json,
308
308
  publicKey,
@@ -319,6 +319,7 @@ export function injectCommands(
319
319
  timeout,
320
320
  debugLogger,
321
321
  log,
322
+ universal,
322
323
  );
323
324
  if (db && address) {
324
325
  await db.storeContract(address, artifactPath, log, alias);
@@ -398,7 +399,9 @@ export function injectCommands(
398
399
  .addOption(createContractAddressOption(db))
399
400
  .addOption(createArtifactOption(db))
400
401
  .addOption(
401
- createSecretKeyOption("The sender's secret key", !db, sk => aliasedSecretKeyParser(sk, db)).conflicts('account'),
402
+ createSigningKeyOption("The sender's signing key", !db, sk => aliasedSigningKeyParser(sk, db)).conflicts(
403
+ 'account',
404
+ ),
402
405
  )
403
406
  .addOption(createAuthwitnessOption('Authorization witness to use for the simulation', !db, db))
404
407
  .addOption(createAccountOption('Alias or address of the account to simulate from', !db, db))
package/src/cmds/send.ts CHANGED
@@ -42,10 +42,10 @@ export async function send(
42
42
  const localStart = performance.now();
43
43
  const sim = await call.simulate({
44
44
  ...sendOptions,
45
- fee: { ...sendOptions.fee, estimateGas: true },
45
+ includeMetadata: true,
46
46
  });
47
- // estimateGas: true guarantees these fields are present
48
- const estimatedGas = sim.estimatedGas!;
47
+ // includeMetadata: true guarantees these fields are present
48
+ const estimatedGas = await wallet.estimateGasLimits(sim.gasUsed!);
49
49
  const stats = sim.stats!;
50
50
 
51
51
  if (feeOpts.estimateOnly) {
@@ -44,7 +44,8 @@ export async function simulate(
44
44
  if (!metadata.instance) {
45
45
  return undefined;
46
46
  }
47
- const artifact = await wallet.getContractArtifact(metadata.instance.currentContractClassId);
47
+ const classId = metadata.updatedContractClassId ?? metadata.instance.originalContractClassId;
48
+ const artifact = await wallet.getContractArtifact(classId);
48
49
  return artifact;
49
50
  },
50
51
  log,
@@ -1,4 +1,5 @@
1
1
  import { Fr } from '@aztec/foundation/curves/bn254';
2
+ import { GrumpkinScalar } from '@aztec/foundation/curves/grumpkin';
2
3
  import type { LogFn } from '@aztec/foundation/log';
3
4
  import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
4
5
  import type { AuthWitness } from '@aztec/stdlib/auth-witness';
@@ -70,17 +71,46 @@ export class WalletDB {
70
71
  return { amount: BigInt(amountStr), secret: secretStr, leafIndex: BigInt(leafIndexStr) };
71
72
  }
72
73
 
74
+ async peekBridgedFeeJuice(recipient: AztecAddress, log: LogFn) {
75
+ const stackPointer =
76
+ (await this.#bridgedFeeJuice.getAsync(`${recipient.toString()}:stackPointer`))?.readInt8() || 0;
77
+ const result = await this.#bridgedFeeJuice.getAsync(`${recipient.toString()}:${stackPointer}`);
78
+ if (!result) {
79
+ throw new Error(
80
+ `No stored fee juice available for recipient ${recipient.toString()}. Please provide claim amount and secret. Stack pointer ${stackPointer}`,
81
+ );
82
+ }
83
+ const [amountStr, secretStr, leafIndexStr] = result.toString().split(':');
84
+ log(`Peeked ${amountStr} fee juice for recipient ${recipient.toString()}. Stack pointer ${stackPointer}`);
85
+ return { amount: BigInt(amountStr), secret: secretStr, leafIndex: BigInt(leafIndexStr) };
86
+ }
87
+
73
88
  async storeAccount(
74
89
  address: AztecAddress,
75
90
  {
76
91
  type,
92
+ signingKey,
77
93
  secretKey,
78
94
  salt,
79
95
  alias,
80
96
  publicKey,
81
- }: { type: AccountType; secretKey: Fr; salt: Fr; alias: string | undefined; publicKey: string | undefined },
97
+ }: {
98
+ type: AccountType;
99
+ signingKey?: GrumpkinScalar;
100
+ secretKey?: Fr;
101
+ salt: Fr;
102
+ alias: string | undefined;
103
+ publicKey: string | undefined;
104
+ },
82
105
  log: LogFn,
83
106
  ) {
107
+ // Even though the privacy secret key is sometimes derived from the signing key, we store it in the database
108
+ // regardless as that is not always the case. Local-key accounts also store their signing key, while external-key
109
+ // accounts such as SSH store only the privacy secret.
110
+ if (!secretKey) {
111
+ throw new Error('Cannot store account without a secret key');
112
+ }
113
+
84
114
  let publicSigningKey: Buffer | undefined;
85
115
  if (type === 'ecdsasecp256r1ssh' && publicKey) {
86
116
  publicSigningKey = extractECDSAPublicKeyFromBase64String(publicKey);
@@ -92,6 +122,9 @@ export class WalletDB {
92
122
  }
93
123
  await this.#accounts.set(`${address.toString()}:type`, Buffer.from(type));
94
124
  await this.#accounts.set(`${address.toString()}:sk`, secretKey.toBuffer());
125
+ if (signingKey) {
126
+ await this.#accounts.set(`${address.toString()}:signing`, signingKey.toBuffer());
127
+ }
95
128
  await this.#accounts.set(`${address.toString()}:salt`, salt.toBuffer());
96
129
  if (publicSigningKey) {
97
130
  await this.#accounts.set(`${address.toString()}:publicSigningKey`, publicSigningKey);
@@ -212,10 +245,13 @@ export class WalletDB {
212
245
  if (!secretKeyBuffer) {
213
246
  throw new Error(`Could not find ${address}:sk. Account "${address.toString}" does not exist on this wallet.`);
214
247
  }
248
+ const signingKeyBuffer = await this.#accounts.getAsync(`${address.toString()}:signing`);
215
249
  const secretKey = Fr.fromBuffer(secretKeyBuffer);
250
+ // External-key accounts (e.g. SSH) store no signing key.
251
+ const signingKey = signingKeyBuffer ? GrumpkinScalar.fromBuffer(signingKeyBuffer) : undefined;
216
252
  const salt = Fr.fromBuffer((await this.#accounts.getAsync(`${address.toString()}:salt`))!);
217
253
  const type = (await this.#accounts.getAsync(`${address.toString()}:type`))!.toString('utf8') as AccountType;
218
- return { address, secretKey, salt, type };
254
+ return { address, signingKey, secretKey, salt, type };
219
255
  }
220
256
 
221
257
  async storeAlias(type: AliasType, key: string, value: Buffer, log: LogFn) {
@@ -2,7 +2,7 @@ import type { ContractArtifact } from '@aztec/aztec.js/abi';
2
2
  import type { AztecAddress } from '@aztec/aztec.js/addresses';
3
3
  import { CallAuthorizationRequest } from '@aztec/aztec.js/authorization';
4
4
  import type { LogFn } from '@aztec/foundation/log';
5
- import { type AbiDecoded, decodeFromAbi, getFunctionArtifact } from '@aztec/stdlib/abi';
5
+ import { decodeEachFromAbi, getFunctionArtifact } from '@aztec/stdlib/abi';
6
6
  import type { OffchainEffect } from '@aztec/stdlib/tx';
7
7
 
8
8
  import { format } from 'util';
@@ -31,10 +31,10 @@ export async function printAuthorizations(
31
31
  );
32
32
  } else {
33
33
  const functionAbi = await getFunctionArtifact(artifact, callAuthorizationRequest.functionSelector);
34
- const callData = decodeFromAbi(
34
+ const callData = decodeEachFromAbi(
35
35
  functionAbi.parameters.map(param => param.type),
36
36
  callAuthorizationRequest.args,
37
- ) as AbiDecoded[];
37
+ );
38
38
  const parameters = functionAbi.parameters.map((param, i) => ({ name: param.name, value: callData[i] }));
39
39
  log(format(' -', `Call authorization. Inner hash: ${callAuthorizationRequest.innerHash.toString()}`));
40
40
  log(format(' ', `Contract: ${artifact.name}@${callAuthorizationEffect.contractAddress}`));
@@ -1,4 +1,10 @@
1
1
  export const MIN_FEE_PADDING = 0.5;
2
2
 
3
- export const AccountTypes = ['schnorr', 'ecdsasecp256r1', 'ecdsasecp256r1ssh', 'ecdsasecp256k1'] as const;
3
+ export const AccountTypes = [
4
+ 'schnorr',
5
+ 'schnorr_initializerless',
6
+ 'ecdsasecp256r1',
7
+ 'ecdsasecp256r1ssh',
8
+ 'ecdsasecp256k1',
9
+ ] as const;
4
10
  export type AccountType = (typeof AccountTypes)[number];
@@ -5,7 +5,7 @@ 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
9
  import type { FeeOptions } from '@aztec/wallet-sdk/base-wallet';
10
10
 
11
11
  import { Option } from 'commander';
@@ -115,6 +115,7 @@ export function parsePaymentMethod(
115
115
  payment: string,
116
116
  log: LogFn,
117
117
  db?: WalletDB,
118
+ estimateOnly?: boolean,
118
119
  ): (wallet: Wallet, from: AztecAddress, gasSettings: GasSettings) => Promise<FeePaymentMethod | undefined> {
119
120
  const parsed = payment.split(',').reduce(
120
121
  (acc, item) => {
@@ -136,7 +137,7 @@ export function parsePaymentMethod(
136
137
  if (!parsed.asset) {
137
138
  throw new Error('Missing "asset" in payment option');
138
139
  }
139
- return AztecAddress.fromString(parsed.asset);
140
+ return AztecAddress.fromStringUnsafe(parsed.asset);
140
141
  };
141
142
 
142
143
  return async (wallet: Wallet, from: AztecAddress, gasSettings: GasSettings) => {
@@ -149,7 +150,7 @@ export function parsePaymentMethod(
149
150
  amount: claimAmount,
150
151
  secret: claimSecret,
151
152
  leafIndex: messageLeafIndex,
152
- } = await db.popBridgedFeeJuice(from, log));
153
+ } = estimateOnly ? await db.peekBridgedFeeJuice(from, log) : await db.popBridgedFeeJuice(from, log));
153
154
  } else {
154
155
  ({ claimAmount, claimSecret, messageLeafIndex } = parsed);
155
156
  }
@@ -157,10 +158,10 @@ export function parsePaymentMethod(
157
158
  const { FeeJuicePaymentMethodWithClaim } = await import('@aztec/aztec.js/fee');
158
159
  return new FeeJuicePaymentMethodWithClaim(from, {
159
160
  claimAmount: (typeof claimAmount === 'string'
160
- ? Fr.fromHexString(claimAmount)
161
+ ? Fr.fromString(claimAmount)
161
162
  : new Fr(claimAmount)
162
163
  ).toBigInt(),
163
- claimSecret: Fr.fromHexString(claimSecret),
164
+ claimSecret: typeof claimSecret === 'string' ? Fr.fromString(claimSecret) : claimSecret,
164
165
  messageLeafIndex: BigInt(messageLeafIndex),
165
166
  });
166
167
  } else {
@@ -256,8 +257,11 @@ export class CLIFeeArgs {
256
257
  ) {}
257
258
 
258
259
  async toUserFeeOptions(node: AztecNode, wallet: Wallet, from: AztecAddress): Promise<ParsedFeeOptions> {
259
- const maxFeesPerGas = (await node.getCurrentMinFees()).mul(1 + MIN_FEE_PADDING);
260
- 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 });
261
265
  const paymentMethod = await this.paymentMethod(wallet, from, gasSettings);
262
266
  return {
263
267
  paymentMethod,
@@ -265,10 +269,32 @@ export class CLIFeeArgs {
265
269
  };
266
270
  }
267
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
+
268
293
  static parse(args: RawCliFeeArgs, log: LogFn, db?: WalletDB): CLIFeeArgs {
294
+ const estimateOnly = !!args.estimateGasOnly;
269
295
  return new CLIFeeArgs(
270
- !!args.estimateGasOnly,
271
- parsePaymentMethod(args.payment ?? 'method=fee_juice', log, db),
296
+ estimateOnly,
297
+ parsePaymentMethod(args.payment ?? 'method=fee_juice', log, db, estimateOnly),
272
298
  parseGasSettings(args),
273
299
  );
274
300
  }
@@ -294,7 +320,7 @@ function formatGasEstimate(estimate: Pick<GasSettings, 'gasLimits' | 'teardownGa
294
320
  }
295
321
 
296
322
  function getEstimatedCost(estimate: Pick<GasSettings, 'gasLimits' | 'teardownGasLimits'>, maxFeesPerGas: GasFees) {
297
- return GasSettings.default({ ...estimate, maxFeesPerGas })
323
+ return GasSettings.fallback({ ...estimate, maxFeesPerGas })
298
324
  .getFeeLimit()
299
325
  .toBigInt();
300
326
  }
@@ -1,5 +1,5 @@
1
1
  import { TxHash } from '@aztec/aztec.js/tx';
2
- import { parseAztecAddress, parseSecretKey, parseTxHash } from '@aztec/cli/utils';
2
+ import { parseAztecAddress, parseSigningKey, parseTxHash } from '@aztec/cli/utils';
3
3
  import { AuthWitness } from '@aztec/stdlib/auth-witness';
4
4
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
5
5
 
@@ -64,13 +64,13 @@ export function aliasedAddressParser(defaultPrefix: AliasType, address: string,
64
64
  }
65
65
  }
66
66
 
67
- export function aliasedSecretKeyParser(sk: string, db?: WalletDB) {
67
+ export function aliasedSigningKeyParser(sk: string, db?: WalletDB) {
68
68
  if (sk.startsWith('0x')) {
69
- return parseSecretKey(sk);
69
+ return parseSigningKey(sk);
70
70
  } else {
71
- const prefixed = `${sk.startsWith('accounts') ? '' : 'accounts'}:${sk.endsWith(':sk') ? sk : `${sk}:sk`}`;
71
+ const prefixed = `${sk.startsWith('accounts') ? '' : 'accounts'}:${sk.endsWith(':signing') ? sk : `${sk}:signing`}`;
72
72
  const rawSk = db ? db.tryRetrieveAlias(prefixed) : sk;
73
- return parseSecretKey(rawSk);
73
+ return parseSigningKey(rawSk);
74
74
  }
75
75
  }
76
76