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

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 (49) hide show
  1. package/dest/bin/index.js +1 -1
  2. package/dest/cmds/check_tx.js +13 -12
  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 +7 -4
  21. package/dest/storage/wallet_db.d.ts.map +1 -1
  22. package/dest/storage/wallet_db.js +15 -1
  23. package/dest/utils/constants.d.ts +2 -2
  24. package/dest/utils/constants.d.ts.map +1 -1
  25. package/dest/utils/constants.js +1 -0
  26. package/dest/utils/options/fees.d.ts +2 -1
  27. package/dest/utils/options/fees.d.ts.map +1 -1
  28. package/dest/utils/options/fees.js +26 -3
  29. package/dest/utils/options/options.d.ts +2 -2
  30. package/dest/utils/options/options.d.ts.map +1 -1
  31. package/dest/utils/options/options.js +5 -5
  32. package/dest/utils/wallet.d.ts +28 -5
  33. package/dest/utils/wallet.d.ts.map +1 -1
  34. package/dest/utils/wallet.js +132 -75
  35. package/package.json +16 -15
  36. package/src/bin/index.ts +1 -1
  37. package/src/cmds/check_tx.ts +14 -13
  38. package/src/cmds/create_account.ts +27 -15
  39. package/src/cmds/deploy.ts +22 -23
  40. package/src/cmds/deploy_account.ts +4 -4
  41. package/src/cmds/import_test_accounts.ts +12 -1
  42. package/src/cmds/index.ts +14 -11
  43. package/src/cmds/send.ts +3 -3
  44. package/src/cmds/simulate.ts +2 -1
  45. package/src/storage/wallet_db.ts +24 -2
  46. package/src/utils/constants.ts +7 -1
  47. package/src/utils/options/fees.ts +28 -4
  48. package/src/utils/options/options.ts +5 -5
  49. package/src/utils/wallet.ts +171 -92
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/cli-wallet",
3
- "version": "0.0.1-commit.a89ec08",
3
+ "version": "0.0.1-commit.aa0c64f",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/cmds/index.js",
@@ -19,7 +19,7 @@
19
19
  "scripts": {
20
20
  "start": "node --no-warnings ./dest/bin",
21
21
  "start:debug": "node --inspect=0.0.0.0:9221 --no-warnings ./dest/bin",
22
- "dev": "LOG_LEVEL=debug && node ./dest/bin",
22
+ "dev": "LOG_LEVEL=\"debug; info: json-rpc, simulator\" node ./dest/bin",
23
23
  "build": "yarn clean && ../scripts/tsc.sh",
24
24
  "build:dev": "../scripts/tsc.sh --watch",
25
25
  "clean": "rm -rf ./dest .tsbuildinfo",
@@ -67,19 +67,20 @@
67
67
  ]
68
68
  },
69
69
  "dependencies": {
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",
70
+ "@aztec/accounts": "0.0.1-commit.aa0c64f",
71
+ "@aztec/aztec.js": "0.0.1-commit.aa0c64f",
72
+ "@aztec/bb.js": "0.0.1-commit.aa0c64f",
73
+ "@aztec/cli": "0.0.1-commit.aa0c64f",
74
+ "@aztec/entrypoints": "0.0.1-commit.aa0c64f",
75
+ "@aztec/ethereum": "0.0.1-commit.aa0c64f",
76
+ "@aztec/foundation": "0.0.1-commit.aa0c64f",
77
+ "@aztec/kv-store": "0.0.1-commit.aa0c64f",
78
+ "@aztec/noir-contracts.js": "0.0.1-commit.aa0c64f",
79
+ "@aztec/noir-noirc_abi": "0.0.1-commit.aa0c64f",
80
+ "@aztec/pxe": "0.0.1-commit.aa0c64f",
81
+ "@aztec/standard-contracts": "0.0.1-commit.aa0c64f",
82
+ "@aztec/stdlib": "0.0.1-commit.aa0c64f",
83
+ "@aztec/wallet-sdk": "0.0.1-commit.aa0c64f",
83
84
  "commander": "^12.1.0",
84
85
  "inquirer": "^10.1.8",
85
86
  "source-map-support": "^0.5.21",
package/src/bin/index.ts CHANGED
@@ -73,7 +73,7 @@ function injectInternalCommands(program: Command, log: LogFn, db: WalletDB) {
73
73
 
74
74
  /** CLI wallet main entrypoint */
75
75
  async function main() {
76
- const walletVersion = getPackageVersion() ?? '0.0.0';
76
+ const walletVersion = getPackageVersion();
77
77
 
78
78
  const db = WalletDB.getInstance();
79
79
  const walletAndNodeWrapper = new CliWalletAndNodeWrapper();
@@ -33,7 +33,7 @@ export async function checkTx(
33
33
  // dependency when dropping PXE JSON RPC Server.
34
34
 
35
35
  async function inspectTx(wallet: CLIWallet, aztecNode: AztecNode, txHash: TxHash, log: LogFn) {
36
- const [receipt, effectsInBlock] = await Promise.all([aztecNode.getTxReceipt(txHash), aztecNode.getTxEffect(txHash)]);
36
+ const receipt = await aztecNode.getTxReceipt(txHash, { includeTxEffect: true });
37
37
  // Base tx data
38
38
  log(`Tx ${txHash.toString()}`);
39
39
  log(` Status: ${receipt.status}`);
@@ -44,11 +44,11 @@ async function inspectTx(wallet: CLIWallet, aztecNode: AztecNode, txHash: TxHash
44
44
  log(` Error: ${receipt.error}`);
45
45
  }
46
46
 
47
- if (!effectsInBlock) {
47
+ if (!receipt.isMined() || !receipt.txEffect) {
48
48
  return;
49
49
  }
50
50
 
51
- const effects = effectsInBlock.data;
51
+ const effects = receipt.txEffect;
52
52
  const artifactMap = await getKnownArtifacts(wallet);
53
53
 
54
54
  log(` Block: ${receipt.blockNumber} (${receipt.blockHash?.toString()})`);
@@ -197,21 +197,22 @@ type ContractArtifactWithClassId = ContractArtifact & { classId: Fr };
197
197
 
198
198
  async function getKnownArtifacts(wallet: CLIWallet): Promise<ArtifactMap> {
199
199
  const knownContractAddresses = await wallet.getContracts();
200
- const knownContracts = (
201
- await Promise.all(knownContractAddresses.map(contractAddress => wallet.getContractMetadata(contractAddress)))
202
- ).map(contractMetadata => contractMetadata.instance);
203
- 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))];
204
206
  const knownArtifacts = (
205
207
  await Promise.all(classIds.map(classId => (classId ? wallet.getContractArtifact(classId) : undefined)))
206
208
  ).map((artifact, index) => (artifact ? { ...artifact, classId: classIds[index] } : undefined));
207
209
  const map: Record<string, ContractArtifactWithClassId> = {};
208
- for (const instance of knownContracts) {
209
- if (instance) {
210
- const artifact = knownArtifacts.find(a =>
211
- a?.classId?.equals(instance.currentContractClassId),
212
- ) 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;
213
214
  if (artifact) {
214
- map[instance.address.toString()] = artifact;
215
+ map[metadata.instance.address.toString()] = artifact;
215
216
  }
216
217
  }
217
218
  }
@@ -1,3 +1,4 @@
1
+ import { deriveSecretKeyFromSigningKey } from '@aztec/accounts/utils';
1
2
  import { NO_FROM } from '@aztec/aztec.js/account';
2
3
  import { AztecAddress } from '@aztec/aztec.js/addresses';
3
4
  import { NO_WAIT } from '@aztec/aztec.js/contracts';
@@ -5,6 +6,7 @@ import { type AztecNode, waitForTx } from '@aztec/aztec.js/node';
5
6
  import type { DeployAccountOptions } from '@aztec/aztec.js/wallet';
6
7
  import { prettyPrintJSON } from '@aztec/cli/cli-utils';
7
8
  import { Fr } from '@aztec/foundation/curves/bn254';
9
+ import { GrumpkinScalar } from '@aztec/foundation/curves/grumpkin';
8
10
  import type { LogFn, Logger } from '@aztec/foundation/log';
9
11
  import { type TxHash, type TxReceipt, TxStatus } from '@aztec/stdlib/tx';
10
12
 
@@ -18,7 +20,7 @@ export async function createAccount(
18
20
  wallet: CLIWallet,
19
21
  aztecNode: AztecNode,
20
22
  accountType: AccountType,
21
- secretKey: Fr | undefined,
23
+ signingKey: GrumpkinScalar | undefined,
22
24
  salt: Fr | undefined,
23
25
  publicKey: string | undefined,
24
26
  alias: string | undefined,
@@ -35,15 +37,17 @@ export async function createAccount(
35
37
  debugLogger: Logger,
36
38
  log: LogFn,
37
39
  ) {
38
- secretKey ??= Fr.random();
39
-
40
- const account = await wallet.createOrRetrieveAccount(
41
- undefined /* address, we don't have it yet */,
42
- secretKey,
43
- accountType,
44
- salt,
45
- publicKey,
46
- );
40
+ let secretKey: Fr;
41
+ if (accountType === 'ecdsasecp256r1ssh') {
42
+ // SSH accounts sign with a key held in the agent, and so we cannot derive their privacy secret key from it. Instead
43
+ // we pick a random value.
44
+ secretKey = Fr.random();
45
+ } else {
46
+ signingKey ??= GrumpkinScalar.random();
47
+ secretKey = await deriveSecretKeyFromSigningKey(signingKey);
48
+ }
49
+
50
+ const account = await wallet.createAccount(accountType, signingKey, secretKey, salt, publicKey);
47
51
  const instanceSalt = account.getInstance().salt;
48
52
  const { address, publicKeys, partialAddress } = await account.getCompleteAddress();
49
53
 
@@ -51,6 +55,9 @@ export async function createAccount(
51
55
  if (json) {
52
56
  out.address = address;
53
57
  out.publicKey = publicKeys;
58
+ if (signingKey) {
59
+ out.signingKey = signingKey;
60
+ }
54
61
  if (secretKey) {
55
62
  out.secretKey = secretKey;
56
63
  }
@@ -61,6 +68,9 @@ export async function createAccount(
61
68
  log(`\nNew account:\n`);
62
69
  log(`Address: ${address.toString()}`);
63
70
  log(`Public key: ${publicKeys.toString()}`);
71
+ if (signingKey) {
72
+ log(`Signing key: ${signingKey.toString()}`);
73
+ }
64
74
  if (secretKey) {
65
75
  log(`Secret key: ${secretKey.toString()}`);
66
76
  }
@@ -71,7 +81,9 @@ export async function createAccount(
71
81
 
72
82
  let txHash: TxHash | undefined;
73
83
  let txReceipt: TxReceipt | undefined;
74
- if (!registerOnly) {
84
+ // Initializerless accounts have no deployment tx — creating one only registers it locally — so there is
85
+ // nothing to deploy on-chain.
86
+ if (!registerOnly && accountType !== 'schnorr_initializerless') {
75
87
  const { paymentMethod, gasSettings } = await feeOpts.toUserFeeOptions(aztecNode, wallet, address);
76
88
 
77
89
  const delegatedDeployment = deployer && !account.address.equals(deployer);
@@ -89,10 +101,10 @@ export async function createAccount(
89
101
  const deployMethod = await account.getDeployMethod();
90
102
  const sim = await deployMethod.simulate({
91
103
  ...deployAccountOpts,
92
- fee: { ...deployAccountOpts.fee, estimateGas: true },
104
+ includeMetadata: true,
93
105
  });
94
- // estimateGas: true guarantees these fields are present
95
- const estimatedGas = sim.estimatedGas!;
106
+ // includeMetadata: true guarantees these fields are present
107
+ const estimatedGas = await wallet.estimateGasLimits(sim.gasUsed!);
96
108
  const stats = sim.stats!;
97
109
 
98
110
  if (feeOpts.estimateOnly) {
@@ -160,5 +172,5 @@ export async function createAccount(
160
172
  }
161
173
  }
162
174
 
163
- return { alias, address, secretKey, salt: instanceSalt };
175
+ return { alias, address, signingKey, secretKey, salt: instanceSalt };
164
176
  }
@@ -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';
@@ -88,13 +89,28 @@ export class WalletDB {
88
89
  address: AztecAddress,
89
90
  {
90
91
  type,
92
+ signingKey,
91
93
  secretKey,
92
94
  salt,
93
95
  alias,
94
96
  publicKey,
95
- }: { 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
+ },
96
105
  log: LogFn,
97
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
+
98
114
  let publicSigningKey: Buffer | undefined;
99
115
  if (type === 'ecdsasecp256r1ssh' && publicKey) {
100
116
  publicSigningKey = extractECDSAPublicKeyFromBase64String(publicKey);
@@ -106,6 +122,9 @@ export class WalletDB {
106
122
  }
107
123
  await this.#accounts.set(`${address.toString()}:type`, Buffer.from(type));
108
124
  await this.#accounts.set(`${address.toString()}:sk`, secretKey.toBuffer());
125
+ if (signingKey) {
126
+ await this.#accounts.set(`${address.toString()}:signing`, signingKey.toBuffer());
127
+ }
109
128
  await this.#accounts.set(`${address.toString()}:salt`, salt.toBuffer());
110
129
  if (publicSigningKey) {
111
130
  await this.#accounts.set(`${address.toString()}:publicSigningKey`, publicSigningKey);
@@ -226,10 +245,13 @@ export class WalletDB {
226
245
  if (!secretKeyBuffer) {
227
246
  throw new Error(`Could not find ${address}:sk. Account "${address.toString}" does not exist on this wallet.`);
228
247
  }
248
+ const signingKeyBuffer = await this.#accounts.getAsync(`${address.toString()}:signing`);
229
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;
230
252
  const salt = Fr.fromBuffer((await this.#accounts.getAsync(`${address.toString()}:salt`))!);
231
253
  const type = (await this.#accounts.getAsync(`${address.toString()}:type`))!.toString('utf8') as AccountType;
232
- return { address, secretKey, salt, type };
254
+ return { address, signingKey, secretKey, salt, type };
233
255
  }
234
256
 
235
257
  async storeAlias(type: AliasType, key: string, value: Buffer, log: LogFn) {
@@ -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';
@@ -137,7 +137,7 @@ export function parsePaymentMethod(
137
137
  if (!parsed.asset) {
138
138
  throw new Error('Missing "asset" in payment option');
139
139
  }
140
- return AztecAddress.fromString(parsed.asset);
140
+ return AztecAddress.fromStringUnsafe(parsed.asset);
141
141
  };
142
142
 
143
143
  return async (wallet: Wallet, from: AztecAddress, gasSettings: GasSettings) => {
@@ -257,8 +257,11 @@ export class CLIFeeArgs {
257
257
  ) {}
258
258
 
259
259
  async toUserFeeOptions(node: AztecNode, wallet: Wallet, from: AztecAddress): Promise<ParsedFeeOptions> {
260
- const maxFeesPerGas = (await node.getCurrentMinFees()).mul(1 + MIN_FEE_PADDING);
261
- const gasSettings = GasSettings.fallback({ ...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 });
262
265
  const paymentMethod = await this.paymentMethod(wallet, from, gasSettings);
263
266
  return {
264
267
  paymentMethod,
@@ -266,6 +269,27 @@ export class CLIFeeArgs {
266
269
  };
267
270
  }
268
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
+
269
293
  static parse(args: RawCliFeeArgs, log: LogFn, db?: WalletDB): CLIFeeArgs {
270
294
  const estimateOnly = !!args.estimateGasOnly;
271
295
  return new CLIFeeArgs(
@@ -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