@aztec/cli 2.1.2 → 2.1.3-rc.2

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.
@@ -37,7 +37,7 @@ const DefaultSlashConfig = {
37
37
  slashExecuteRoundsLookBack: 4
38
38
  };
39
39
  const DefaultNetworkDBMapSizeConfig = {
40
- dbMapSizeKb: defaultDBMapSizeKb,
40
+ dataStoreMapSizeKb: defaultDBMapSizeKb,
41
41
  archiverStoreMapSizeKb: tbMapSizeKb,
42
42
  noteHashTreeMapSizeKb: tbMapSizeKb,
43
43
  nullifierTreeMapSizeKb: tbMapSizeKb,
@@ -49,16 +49,17 @@ export const stagingIgnitionL2ChainConfig = {
49
49
  sponsoredFPC: false,
50
50
  disableTransactions: true,
51
51
  p2pEnabled: true,
52
- p2pBootstrapNodes: [],
53
- seqMinTxsPerBlock: 0,
54
- seqMaxTxsPerBlock: 0,
52
+ bootstrapNodes: [],
53
+ minTxsPerBlock: 0,
54
+ maxTxsPerBlock: 0,
55
55
  realProofs: true,
56
56
  snapshotsUrls: [
57
57
  `${SNAPSHOTS_URL}/staging-ignition/`
58
58
  ],
59
59
  autoUpdate: 'config-and-version',
60
60
  autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/staging-ignition.json',
61
- maxTxPoolSize: 100_000_000,
61
+ maxTxPoolSize: 0,
62
+ publicMetricsOptOut: false,
62
63
  publicIncludeMetrics,
63
64
  publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
64
65
  publicMetricsCollectFrom: [
@@ -116,15 +117,16 @@ export const stagingPublicL2ChainConfig = {
116
117
  sponsoredFPC: true,
117
118
  disableTransactions: false,
118
119
  p2pEnabled: true,
119
- p2pBootstrapNodes: [],
120
- seqMinTxsPerBlock: 0,
121
- seqMaxTxsPerBlock: 20,
120
+ bootstrapNodes: [],
121
+ minTxsPerBlock: 0,
122
+ maxTxsPerBlock: 20,
122
123
  realProofs: true,
123
124
  snapshotsUrls: [
124
125
  `${SNAPSHOTS_URL}/staging-public/`
125
126
  ],
126
127
  autoUpdate: 'config-and-version',
127
128
  autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/staging-public.json',
129
+ publicMetricsOptOut: false,
128
130
  publicIncludeMetrics,
129
131
  publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
130
132
  publicMetricsCollectFrom: [
@@ -150,15 +152,54 @@ export const stagingPublicL2ChainConfig = {
150
152
  ...DefaultSlashConfig,
151
153
  ...DefaultNetworkDBMapSizeConfig
152
154
  };
155
+ export const nextNetL2ChainConfig = {
156
+ l1ChainId: 11155111,
157
+ testAccounts: true,
158
+ sponsoredFPC: true,
159
+ p2pEnabled: true,
160
+ disableTransactions: false,
161
+ bootstrapNodes: [],
162
+ minTxsPerBlock: 0,
163
+ maxTxsPerBlock: 8,
164
+ realProofs: true,
165
+ snapshotsUrls: [],
166
+ autoUpdate: 'config-and-version',
167
+ autoUpdateUrl: '',
168
+ publicMetricsOptOut: true,
169
+ publicIncludeMetrics,
170
+ publicMetricsCollectorUrl: '',
171
+ publicMetricsCollectFrom: [
172
+ ''
173
+ ],
174
+ maxTxPoolSize: 100_000_000,
175
+ txPoolDeleteTxsAfterReorg: false,
176
+ // Deployment stuff
177
+ /** How many seconds an L1 slot lasts. */ ethereumSlotDuration: 12,
178
+ /** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */ aztecSlotDuration: 36,
179
+ /** How many L2 slots an epoch lasts. */ aztecEpochDuration: 32,
180
+ /** The target validator committee size. */ aztecTargetCommitteeSize: 48,
181
+ /** The number of epochs to lag behind the current epoch for validator selection. */ lagInEpochs: DefaultL1ContractsConfig.lagInEpochs,
182
+ /** The local ejection threshold for a validator. Stricter than ejectionThreshold but local to a specific rollup */ localEjectionThreshold: DefaultL1ContractsConfig.localEjectionThreshold,
183
+ /** The number of epochs after an epoch ends that proofs are still accepted. */ aztecProofSubmissionEpochs: 1,
184
+ /** The deposit amount for a validator */ activationThreshold: DefaultL1ContractsConfig.activationThreshold,
185
+ /** The minimum stake for a validator. */ ejectionThreshold: DefaultL1ContractsConfig.ejectionThreshold,
186
+ /** The slashing round size */ slashingRoundSizeInEpochs: DefaultL1ContractsConfig.slashingRoundSizeInEpochs,
187
+ /** Governance proposing round size */ governanceProposerRoundSize: DefaultL1ContractsConfig.governanceProposerRoundSize,
188
+ /** The mana target for the rollup */ manaTarget: DefaultL1ContractsConfig.manaTarget,
189
+ /** The proving cost per mana */ provingCostPerMana: DefaultL1ContractsConfig.provingCostPerMana,
190
+ /** Exit delay for stakers */ exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
191
+ ...DefaultSlashConfig,
192
+ ...DefaultNetworkDBMapSizeConfig
193
+ };
153
194
  export const testnetL2ChainConfig = {
154
195
  l1ChainId: 11155111,
155
196
  testAccounts: false,
156
197
  sponsoredFPC: true,
157
198
  p2pEnabled: true,
158
199
  disableTransactions: true,
159
- p2pBootstrapNodes: [],
160
- seqMinTxsPerBlock: 0,
161
- seqMaxTxsPerBlock: 0,
200
+ bootstrapNodes: [],
201
+ minTxsPerBlock: 0,
202
+ maxTxsPerBlock: 0,
162
203
  realProofs: true,
163
204
  snapshotsUrls: [
164
205
  `${SNAPSHOTS_URL}/testnet/`
@@ -166,6 +207,7 @@ export const testnetL2ChainConfig = {
166
207
  autoUpdate: 'config-and-version',
167
208
  autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/testnet.json',
168
209
  maxTxPoolSize: 100_000_000,
210
+ publicMetricsOptOut: false,
169
211
  publicIncludeMetrics,
170
212
  publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
171
213
  publicMetricsCollectFrom: [
@@ -226,21 +268,23 @@ export const mainnetL2ChainConfig = {
226
268
  testAccounts: false,
227
269
  sponsoredFPC: false,
228
270
  p2pEnabled: true,
229
- p2pBootstrapNodes: [],
230
- seqMinTxsPerBlock: 0,
231
- seqMaxTxsPerBlock: 0,
271
+ bootstrapNodes: [],
272
+ minTxsPerBlock: 0,
273
+ maxTxsPerBlock: 0,
232
274
  realProofs: true,
233
275
  snapshotsUrls: [
234
276
  `${SNAPSHOTS_URL}/mainnet/`
235
277
  ],
236
278
  autoUpdate: 'notify',
237
279
  autoUpdateUrl: 'https://storage.googleapis.com/aztec-mainnet/auto-update/mainnet.json',
238
- maxTxPoolSize: 100_000_000,
280
+ maxTxPoolSize: 0,
281
+ publicMetricsOptOut: true,
239
282
  publicIncludeMetrics,
240
283
  publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
241
284
  publicMetricsCollectFrom: [
242
285
  'sequencer'
243
286
  ],
287
+ blobAllowEmptySources: true,
244
288
  /** How many seconds an L1 slot lasts. */ ethereumSlotDuration: 12,
245
289
  /** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */ aztecSlotDuration: 72,
246
290
  /** How many L2 slots an epoch lasts. */ aztecEpochDuration: 32,
@@ -252,7 +296,7 @@ export const mainnetL2ChainConfig = {
252
296
  slashingRoundSizeInEpochs: 4,
253
297
  slashingExecutionDelayInRounds: 28,
254
298
  slashingLifetimeInRounds: 34,
255
- slashingVetoer: EthAddress.ZERO,
299
+ slashingVetoer: EthAddress.fromString('0xBbB4aF368d02827945748b28CD4b2D42e4A37480'),
256
300
  slashingOffsetInRounds: 2,
257
301
  slashingDisableDuration: 259_200,
258
302
  slasherFlavor: 'tally',
@@ -285,6 +329,45 @@ export const mainnetL2ChainConfig = {
285
329
  sentinelEnabled: true,
286
330
  ...DefaultNetworkDBMapSizeConfig
287
331
  };
332
+ export const devnetL2ChainConfig = {
333
+ l1ChainId: 11155111,
334
+ testAccounts: true,
335
+ sponsoredFPC: true,
336
+ p2pEnabled: true,
337
+ disableTransactions: false,
338
+ bootstrapNodes: [],
339
+ minTxsPerBlock: 0,
340
+ maxTxsPerBlock: 8,
341
+ realProofs: false,
342
+ snapshotsUrls: [],
343
+ autoUpdate: 'config-and-version',
344
+ autoUpdateUrl: '',
345
+ publicMetricsOptOut: true,
346
+ publicIncludeMetrics,
347
+ publicMetricsCollectorUrl: '',
348
+ publicMetricsCollectFrom: [
349
+ ''
350
+ ],
351
+ maxTxPoolSize: 100_000_000,
352
+ txPoolDeleteTxsAfterReorg: true,
353
+ // Deployment stuff
354
+ /** How many seconds an L1 slot lasts. */ ethereumSlotDuration: 12,
355
+ /** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */ aztecSlotDuration: 36,
356
+ /** How many L2 slots an epoch lasts. */ aztecEpochDuration: 8,
357
+ /** The target validator committee size. */ aztecTargetCommitteeSize: 1,
358
+ /** The number of epochs to lag behind the current epoch for validator selection. */ lagInEpochs: 1,
359
+ /** The local ejection threshold for a validator. Stricter than ejectionThreshold but local to a specific rollup */ localEjectionThreshold: DefaultL1ContractsConfig.localEjectionThreshold,
360
+ /** The number of epochs after an epoch ends that proofs are still accepted. */ aztecProofSubmissionEpochs: 1,
361
+ /** The deposit amount for a validator */ activationThreshold: DefaultL1ContractsConfig.activationThreshold,
362
+ /** The minimum stake for a validator. */ ejectionThreshold: DefaultL1ContractsConfig.ejectionThreshold,
363
+ /** The slashing round size */ slashingRoundSizeInEpochs: DefaultL1ContractsConfig.slashingRoundSizeInEpochs,
364
+ /** Governance proposing round size */ governanceProposerRoundSize: DefaultL1ContractsConfig.governanceProposerRoundSize,
365
+ /** The mana target for the rollup */ manaTarget: DefaultL1ContractsConfig.manaTarget,
366
+ /** The proving cost per mana */ provingCostPerMana: DefaultL1ContractsConfig.provingCostPerMana,
367
+ /** Exit delay for stakers */ exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
368
+ ...DefaultSlashConfig,
369
+ ...DefaultNetworkDBMapSizeConfig
370
+ };
288
371
  export function getL2ChainConfig(networkName) {
289
372
  let config;
290
373
  if (networkName === 'staging-public') {
@@ -309,7 +392,7 @@ export function getL2ChainConfig(networkName) {
309
392
  function getDefaultDataDir(networkName) {
310
393
  return path.join(process.env.HOME || '~', '.aztec', networkName, 'data');
311
394
  }
312
- export function enrichEnvironmentWithChainConfig(networkName) {
395
+ export function enrichEnvironmentWithChainName(networkName) {
313
396
  if (networkName === 'local') {
314
397
  return;
315
398
  }
@@ -318,18 +401,22 @@ export function enrichEnvironmentWithChainConfig(networkName) {
318
401
  if (!config) {
319
402
  throw new Error(`Unknown network name: ${networkName}`);
320
403
  }
321
- enrichVar('BOOTSTRAP_NODES', config.p2pBootstrapNodes.join(','));
404
+ enrichEnvironmentWithChainConfig(config);
405
+ }
406
+ export function enrichEnvironmentWithChainConfig(config) {
407
+ enrichVar('BOOTSTRAP_NODES', config.bootstrapNodes.join(','));
322
408
  enrichVar('TEST_ACCOUNTS', config.testAccounts.toString());
323
409
  enrichVar('SPONSORED_FPC', config.sponsoredFPC.toString());
324
410
  enrichVar('P2P_ENABLED', config.p2pEnabled.toString());
325
411
  enrichVar('L1_CHAIN_ID', config.l1ChainId.toString());
326
- enrichVar('SEQ_MIN_TX_PER_BLOCK', config.seqMinTxsPerBlock.toString());
327
- enrichVar('SEQ_MAX_TX_PER_BLOCK', config.seqMaxTxsPerBlock.toString());
412
+ enrichVar('SEQ_MIN_TX_PER_BLOCK', config.minTxsPerBlock.toString());
413
+ enrichVar('SEQ_MAX_TX_PER_BLOCK', config.maxTxsPerBlock.toString());
328
414
  enrichVar('PROVER_REAL_PROOFS', config.realProofs.toString());
329
415
  enrichVar('PXE_PROVER_ENABLED', config.realProofs.toString());
330
416
  enrichVar('SYNC_SNAPSHOTS_URLS', config.snapshotsUrls.join(','));
331
417
  enrichVar('P2P_MAX_TX_POOL_SIZE', config.maxTxPoolSize.toString());
332
- enrichVar('DATA_STORE_MAP_SIZE_KB', config.dbMapSizeKb.toString());
418
+ enrichVar('P2P_TX_POOL_DELETE_TXS_AFTER_REORG', config.txPoolDeleteTxsAfterReorg.toString());
419
+ enrichVar('DATA_STORE_MAP_SIZE_KB', config.dataStoreMapSizeKb.toString());
333
420
  enrichVar('ARCHIVER_STORE_MAP_SIZE_KB', config.archiverStoreMapSizeKb.toString());
334
421
  enrichVar('NOTE_HASH_TREE_MAP_SIZE_KB', config.noteHashTreeMapSizeKb.toString());
335
422
  enrichVar('NULLIFIER_TREE_MAP_SIZE_KB', config.nullifierTreeMapSizeKb.toString());
@@ -355,11 +442,13 @@ export function enrichEnvironmentWithChainConfig(networkName) {
355
442
  if (config.publicMetricsCollectFrom) {
356
443
  enrichVar('PUBLIC_OTEL_COLLECT_FROM', config.publicMetricsCollectFrom.join(','));
357
444
  }
445
+ enrichVar('PUBLIC_OTEL_OPT_OUT', config.publicMetricsOptOut.toString());
358
446
  // Deployment stuff
359
447
  enrichVar('ETHEREUM_SLOT_DURATION', config.ethereumSlotDuration.toString());
360
448
  enrichVar('AZTEC_SLOT_DURATION', config.aztecSlotDuration.toString());
361
449
  enrichVar('AZTEC_EPOCH_DURATION', config.aztecEpochDuration.toString());
362
450
  enrichVar('AZTEC_TARGET_COMMITTEE_SIZE', config.aztecTargetCommitteeSize.toString());
451
+ enrichVar('AZTEC_LAG_IN_EPOCHS', config.lagInEpochs.toString());
363
452
  enrichVar('AZTEC_PROOF_SUBMISSION_EPOCHS', config.aztecProofSubmissionEpochs.toString());
364
453
  enrichVar('AZTEC_ACTIVATION_THRESHOLD', config.activationThreshold.toString());
365
454
  enrichVar('AZTEC_EJECTION_THRESHOLD', config.ejectionThreshold.toString());
@@ -377,6 +466,7 @@ export function enrichEnvironmentWithChainConfig(networkName) {
377
466
  enrichVar('AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS', config.slashingExecutionDelayInRounds.toString());
378
467
  enrichVar('AZTEC_SLASHING_OFFSET_IN_ROUNDS', config.slashingOffsetInRounds.toString());
379
468
  enrichVar('AZTEC_SLASHER_FLAVOR', config.slasherFlavor);
469
+ enrichVar('AZTEC_SLASHING_DISABLE_DURATION', config.slashingDisableDuration.toString());
380
470
  enrichVar('AZTEC_EXIT_DELAY_SECONDS', config.exitDelaySeconds.toString());
381
471
  enrichEthAddressVar('AZTEC_SLASHING_VETOER', config.slashingVetoer.toString());
382
472
  // Slashing
@@ -393,6 +483,8 @@ export function enrichEnvironmentWithChainConfig(networkName) {
393
483
  enrichVar('SLASH_INVALID_BLOCK_PENALTY', config.slashBroadcastedInvalidBlockPenalty.toString());
394
484
  enrichVar('SLASH_OFFENSE_EXPIRATION_ROUNDS', config.slashOffenseExpirationRounds.toString());
395
485
  enrichVar('SLASH_MAX_PAYLOAD_SIZE', config.slashMaxPayloadSize.toString());
486
+ enrichVar('SLASH_GRACE_PERIOD_L2_SLOTS', config.slashGracePeriodL2Slots.toString());
487
+ enrichVar('SLASH_EXECUTE_ROUNDS_LOOK_BACK', config.slashExecuteRoundsLookBack.toString());
396
488
  enrichVar('SENTINEL_ENABLED', config.sentinelEnabled.toString());
397
489
  enrichVar('TRANSACTIONS_DISABLED', config.disableTransactions.toString());
398
490
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/cli",
3
- "version": "2.1.2",
3
+ "version": "2.1.3-rc.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./contracts": "./dest/cmds/contracts/index.js",
@@ -71,18 +71,18 @@
71
71
  ]
72
72
  },
73
73
  "dependencies": {
74
- "@aztec/archiver": "2.1.2",
75
- "@aztec/aztec.js": "2.1.2",
76
- "@aztec/constants": "2.1.2",
77
- "@aztec/entrypoints": "2.1.2",
78
- "@aztec/ethereum": "2.1.2",
79
- "@aztec/foundation": "2.1.2",
80
- "@aztec/l1-artifacts": "2.1.2",
81
- "@aztec/node-keystore": "2.1.2",
82
- "@aztec/node-lib": "2.1.2",
83
- "@aztec/p2p": "2.1.2",
84
- "@aztec/stdlib": "2.1.2",
85
- "@aztec/world-state": "2.1.2",
74
+ "@aztec/archiver": "2.1.3-rc.2",
75
+ "@aztec/aztec.js": "2.1.3-rc.2",
76
+ "@aztec/constants": "2.1.3-rc.2",
77
+ "@aztec/entrypoints": "2.1.3-rc.2",
78
+ "@aztec/ethereum": "2.1.3-rc.2",
79
+ "@aztec/foundation": "2.1.3-rc.2",
80
+ "@aztec/l1-artifacts": "2.1.3-rc.2",
81
+ "@aztec/node-keystore": "2.1.3-rc.2",
82
+ "@aztec/node-lib": "2.1.3-rc.2",
83
+ "@aztec/p2p": "2.1.3-rc.2",
84
+ "@aztec/stdlib": "2.1.3-rc.2",
85
+ "@aztec/world-state": "2.1.3-rc.2",
86
86
  "@ethersproject/wallet": "^5.8.0",
87
87
  "@iarna/toml": "^2.2.5",
88
88
  "@libp2p/peer-id-factory": "^3.0.4",
@@ -96,8 +96,11 @@
96
96
  "viem": "npm:@spalladino/viem@2.38.2-eip7594.0"
97
97
  },
98
98
  "devDependencies": {
99
- "@aztec/accounts": "2.1.2",
100
- "@aztec/protocol-contracts": "2.1.2",
99
+ "@aztec/accounts": "2.1.3-rc.2",
100
+ "@aztec/aztec-node": "2.1.3-rc.2",
101
+ "@aztec/kv-store": "2.1.3-rc.2",
102
+ "@aztec/protocol-contracts": "2.1.3-rc.2",
103
+ "@aztec/telemetry-client": "2.1.3-rc.2",
101
104
  "@jest/globals": "^30.0.0",
102
105
  "@types/jest": "^30.0.0",
103
106
  "@types/lodash.chunk": "^4.2.9",
@@ -113,15 +116,15 @@
113
116
  "typescript": "^5.3.3"
114
117
  },
115
118
  "peerDependencies": {
116
- "@aztec/accounts": "2.1.2",
117
- "@aztec/bb-prover": "2.1.2",
118
- "@aztec/ethereum": "2.1.2",
119
- "@aztec/l1-artifacts": "2.1.2",
120
- "@aztec/noir-contracts.js": "2.1.2",
121
- "@aztec/noir-protocol-circuits-types": "2.1.2",
122
- "@aztec/noir-test-contracts.js": "2.1.2",
123
- "@aztec/protocol-contracts": "2.1.2",
124
- "@aztec/stdlib": "2.1.2"
119
+ "@aztec/accounts": "2.1.3-rc.2",
120
+ "@aztec/bb-prover": "2.1.3-rc.2",
121
+ "@aztec/ethereum": "2.1.3-rc.2",
122
+ "@aztec/l1-artifacts": "2.1.3-rc.2",
123
+ "@aztec/noir-contracts.js": "2.1.3-rc.2",
124
+ "@aztec/noir-protocol-circuits-types": "2.1.3-rc.2",
125
+ "@aztec/noir-test-contracts.js": "2.1.3-rc.2",
126
+ "@aztec/protocol-contracts": "2.1.3-rc.2",
127
+ "@aztec/stdlib": "2.1.3-rc.2"
125
128
  },
126
129
  "files": [
127
130
  "dest",
@@ -30,7 +30,6 @@ export async function addValidatorKeys(existing: string, options: AddValidatorKe
30
30
  addressIndex,
31
31
  ikm,
32
32
  blsPath,
33
- blsOnly,
34
33
  json,
35
34
  feeRecipient: feeRecipientOpt,
36
35
  coinbase: coinbaseOpt,
@@ -75,7 +74,6 @@ export async function addValidatorKeys(existing: string, options: AddValidatorKe
75
74
  mnemonic: mnemonicToUse,
76
75
  ikm,
77
76
  blsPath,
78
- blsOnly,
79
77
  feeRecipient,
80
78
  coinbase,
81
79
  remoteSigner,
@@ -7,7 +7,7 @@ import { parseAztecAddress, parseEthereumAddress, parseHex, parseOptionalInteger
7
7
  export function injectCommands(program: Command, log: LogFn) {
8
8
  const group = program
9
9
  .command('validator-keys')
10
- .aliases(['valKeys'])
10
+ .aliases(['valKeys', 'valkeys'])
11
11
  .description('Manage validator keystores for node operators');
12
12
 
13
13
  group
@@ -29,13 +29,23 @@ export function injectCommands(program: Command, log: LogFn) {
29
29
  .option('--remote-signer <url>', 'Default remote signer URL for accounts in this file')
30
30
  .option('--ikm <hex>', 'Initial keying material for BLS (alternative to mnemonic)', value => parseHex(value, 32))
31
31
  .option('--bls-path <path>', 'EIP-2334 path (default m/12381/3600/0/0/0)')
32
- .option('--bls-only', 'Generate only BLS keys')
33
32
  .option(
34
33
  '--password <str>',
35
34
  'Password for writing keystore files (ETH JSON V3 and BLS EIP-2335). Empty string allowed',
36
35
  )
37
36
  .option('--out-dir <dir>', 'Output directory for generated keystore file(s)')
38
37
  .option('--json', 'Echo resulting JSON to stdout')
38
+ .option('--staker-output', 'Generate staker output JSON files for each attester')
39
+ .option('--gse-address <address>', 'GSE contract address (required with --staker-output)', parseEthereumAddress)
40
+ .option('--l1-rpc-urls <urls>', 'L1 RPC URLs (comma-separated, required with --staker-output)', value =>
41
+ value.split(','),
42
+ )
43
+ .option(
44
+ '-c, --l1-chain-id <number>',
45
+ 'L1 chain ID (required with --staker-output)',
46
+ value => parseInt(value),
47
+ 31337,
48
+ )
39
49
  .requiredOption('--fee-recipient <address>', 'Aztec address that will receive fees', parseAztecAddress)
40
50
  .action(async options => {
41
51
  const { newValidatorKeystore } = await import('./new.js');
@@ -62,7 +72,6 @@ export function injectCommands(program: Command, log: LogFn) {
62
72
  .option('--remote-signer <url>', 'Default remote signer URL for accounts in this file')
63
73
  .option('--ikm <hex>', 'Initial keying material for BLS (alternative to mnemonic)', value => parseHex(value, 32))
64
74
  .option('--bls-path <path>', 'EIP-2334 path (default m/12381/3600/0/0/0)')
65
- .option('--bls-only', 'Generate only BLS keys')
66
75
  .option('--empty', 'Generate an empty skeleton without keys')
67
76
  .option(
68
77
  '--password <str>',
@@ -76,6 +85,25 @@ export function injectCommands(program: Command, log: LogFn) {
76
85
  await addValidatorKeys(existing, options, log);
77
86
  });
78
87
 
88
+ group
89
+ .command('staker')
90
+ .summary('Generate staking JSON from keystore')
91
+ .description(
92
+ 'Reads a validator keystore and outputs staking data with BLS public keys for each attester (skips mnemonics)',
93
+ )
94
+ .requiredOption('--from <keystore>', 'Path to keystore JSON file')
95
+ .option('--password <password>', 'Password for decrypting encrypted keystores (if not specified in keystore file)')
96
+ .requiredOption('--gse-address <address>', 'GSE contract address', parseEthereumAddress)
97
+ .option('--l1-rpc-urls <urls>', 'L1 RPC URLs (comma-separated)', value => value.split(','), [
98
+ 'http://localhost:8545',
99
+ ])
100
+ .option('-c, --l1-chain-id <number>', 'L1 chain ID', value => parseInt(value), 31337)
101
+ .option('--output <file>', 'Output file path (if not specified, JSON is written to stdout)')
102
+ .action(async options => {
103
+ const { generateStakerJson } = await import('./staker.js');
104
+ await generateStakerJson(options, log);
105
+ });
106
+
79
107
  // top-level convenience: aztec generate-bls-keypair
80
108
  program
81
109
  .command('generate-bls-keypair')
@@ -1,9 +1,13 @@
1
+ import { prettyPrintJSON } from '@aztec/cli/utils';
2
+ import { GSEContract, createEthereumChain } from '@aztec/ethereum';
1
3
  import type { EthAddress } from '@aztec/foundation/eth-address';
2
4
  import type { LogFn } from '@aztec/foundation/log';
3
5
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
6
 
5
7
  import { wordlist } from '@scure/bip39/wordlists/english.js';
6
- import { dirname } from 'path';
8
+ import { writeFile } from 'fs/promises';
9
+ import { basename, dirname, join } from 'path';
10
+ import { createPublicClient, fallback, http } from 'viem';
7
11
  import { generateMnemonic, mnemonicToAccount } from 'viem/accounts';
8
12
 
9
13
  import {
@@ -15,6 +19,7 @@ import {
15
19
  writeEthJsonV3ToFile,
16
20
  writeKeystoreFile,
17
21
  } from './shared.js';
22
+ import { processAttesterAccounts } from './staker.js';
18
23
 
19
24
  export type NewValidatorKeystoreOptions = {
20
25
  dataDir?: string;
@@ -28,7 +33,6 @@ export type NewValidatorKeystoreOptions = {
28
33
  separatePublisher?: boolean;
29
34
  ikm?: string;
30
35
  blsPath?: string;
31
- blsOnly?: boolean;
32
36
  password?: string;
33
37
  outDir?: string;
34
38
  json?: boolean;
@@ -36,6 +40,10 @@ export type NewValidatorKeystoreOptions = {
36
40
  coinbase?: EthAddress;
37
41
  remoteSigner?: string;
38
42
  fundingAccount?: EthAddress;
43
+ stakerOutput?: boolean;
44
+ gseAddress?: EthAddress;
45
+ l1RpcUrls?: string[];
46
+ l1ChainId?: number;
39
47
  };
40
48
 
41
49
  export async function newValidatorKeystore(options: NewValidatorKeystoreOptions, log: LogFn) {
@@ -51,14 +59,30 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
51
59
  feeRecipient,
52
60
  remoteSigner,
53
61
  fundingAccount,
54
- blsOnly,
55
62
  blsPath,
56
63
  ikm,
57
64
  mnemonic: _mnemonic,
58
65
  password,
59
66
  outDir,
67
+ stakerOutput,
68
+ gseAddress,
69
+ l1RpcUrls,
70
+ l1ChainId,
60
71
  } = options;
61
72
 
73
+ // Validate staker output requirements
74
+ if (stakerOutput) {
75
+ if (!gseAddress) {
76
+ throw new Error('--gse-address is required when using --staker-output');
77
+ }
78
+ if (!l1RpcUrls || l1RpcUrls.length === 0) {
79
+ throw new Error('--l1-rpc-urls is required when using --staker-output');
80
+ }
81
+ if (l1ChainId === undefined) {
82
+ throw new Error('--l1-chain-id is required when using --staker-output');
83
+ }
84
+ }
85
+
62
86
  if (remoteSigner && !_mnemonic) {
63
87
  throw new Error(
64
88
  'Using --remote-signer requires a deterministic key source. Provide --mnemonic to derive keys, or omit --remote-signer to write new private keys to keystore.',
@@ -67,6 +91,14 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
67
91
 
68
92
  const mnemonic = _mnemonic ?? generateMnemonic(wordlist);
69
93
 
94
+ if (!_mnemonic && !json) {
95
+ log('No mnemonic provided, generating new one...');
96
+ log(`Using new mnemonic:`);
97
+ log('');
98
+ log(mnemonic);
99
+ log('');
100
+ }
101
+
70
102
  const validatorCount = typeof count === 'number' && Number.isFinite(count) && count > 0 ? Math.floor(count) : 1;
71
103
  const { outputPath } = await resolveKeystoreOutputPath(dataDir, file);
72
104
 
@@ -78,7 +110,6 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
78
110
  mnemonic,
79
111
  ikm,
80
112
  blsPath,
81
- blsOnly,
82
113
  feeRecipient,
83
114
  coinbase,
84
115
  remoteSigner,
@@ -99,15 +130,66 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
99
130
 
100
131
  await writeKeystoreFile(outputPath, keystore);
101
132
 
102
- maybePrintJson(log, json, keystore as unknown as Record<string, any>);
103
- if (!json) {
133
+ // Generate staker outputs if requested
134
+ const allStakerOutputs: any[] = [];
135
+ if (stakerOutput && gseAddress && l1RpcUrls && l1ChainId !== undefined) {
136
+ const chain = createEthereumChain(l1RpcUrls, l1ChainId);
137
+ const publicClient = createPublicClient({
138
+ chain: chain.chainInfo,
139
+ transport: fallback(l1RpcUrls.map(url => http(url))),
140
+ });
141
+ const gse = new GSEContract(publicClient, gseAddress);
142
+
143
+ const keystoreOutDir = outDir && outDir.length > 0 ? outDir : dirname(outputPath);
144
+ // Extract keystore base name without extension for unique staker output filenames
145
+ const keystoreBaseName = basename(outputPath, '.json');
146
+
147
+ // Process each validator
148
+ for (let i = 0; i < validators.length; i++) {
149
+ const validator = validators[i];
150
+ const outputs = await processAttesterAccounts(validator.attester, gse, password);
151
+
152
+ // Save each attester's staker output
153
+ for (let j = 0; j < outputs.length; j++) {
154
+ const attesterIndex = i + 1;
155
+ const stakerOutputPath = join(
156
+ keystoreOutDir,
157
+ `${keystoreBaseName}_attester${attesterIndex}_staker_output.json`,
158
+ );
159
+ await writeFile(stakerOutputPath, prettyPrintJSON(outputs[j]), 'utf-8');
160
+ allStakerOutputs.push(outputs[j]);
161
+ }
162
+ }
163
+ }
164
+
165
+ const outputData = !_mnemonic ? { ...keystore, generatedMnemonic: mnemonic } : keystore;
166
+
167
+ // Handle JSON output
168
+ if (json) {
169
+ if (stakerOutput && allStakerOutputs.length > 0) {
170
+ const combinedOutput = {
171
+ keystore: outputData,
172
+ staker: allStakerOutputs,
173
+ };
174
+ maybePrintJson(log, json, combinedOutput as unknown as Record<string, any>);
175
+ } else {
176
+ maybePrintJson(log, json, outputData as unknown as Record<string, any>);
177
+ }
178
+ } else {
104
179
  log(`Wrote validator keystore to ${outputPath}`);
180
+ if (stakerOutput && allStakerOutputs.length > 0) {
181
+ const keystoreOutDir = outDir && outDir.length > 0 ? outDir : dirname(outputPath);
182
+ log(`Wrote ${allStakerOutputs.length} staker output file(s) to ${keystoreOutDir}`);
183
+ log('');
184
+ }
105
185
  }
106
186
 
107
- // Always print a concise summary of public keys (addresses and BLS pubkeys)
108
- logValidatorSummaries(log, summaries);
187
+ // print a concise summary of public keys (addresses and BLS pubkeys) if no --json options was selected
188
+ if (!json) {
189
+ logValidatorSummaries(log, summaries);
190
+ }
109
191
 
110
- if (!blsOnly && mnemonic && remoteSigner) {
192
+ if (mnemonic && remoteSigner && !json) {
111
193
  for (let i = 0; i < validatorCount; i++) {
112
194
  const addrIdx = addressIndex + i;
113
195
  const acct = mnemonicToAccount(mnemonic, {
@@ -117,4 +199,10 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
117
199
  log(`attester address: ${acct.address} remoteSignerUrl: ${remoteSigner}`);
118
200
  }
119
201
  }
202
+
203
+ // Log staker outputs if not in JSON mode
204
+ if (!json && stakerOutput && allStakerOutputs.length > 0) {
205
+ log('\nStaker outputs:');
206
+ log(prettyPrintJSON(allStakerOutputs));
207
+ }
120
208
  }
@@ -23,7 +23,6 @@ export type BuildValidatorsInput = {
23
23
  mnemonic: string;
24
24
  ikm?: string;
25
25
  blsPath?: string;
26
- blsOnly?: boolean;
27
26
  feeRecipient: AztecAddress;
28
27
  coinbase?: EthAddress;
29
28
  remoteSigner?: string;
@@ -69,7 +68,6 @@ export async function buildValidatorEntries(input: BuildValidatorsInput) {
69
68
  mnemonic,
70
69
  ikm,
71
70
  blsPath,
72
- blsOnly,
73
71
  feeRecipient,
74
72
  coinbase,
75
73
  remoteSigner,
@@ -85,15 +83,9 @@ export async function buildValidatorEntries(input: BuildValidatorsInput) {
85
83
  const basePath = blsPath ?? defaultBlsPath;
86
84
  const perValidatorPath = withValidatorIndex(basePath, addressIndex);
87
85
 
88
- const blsPrivKey = blsOnly || ikm || mnemonic ? deriveBlsPrivateKey(mnemonic, ikm, perValidatorPath) : undefined;
86
+ const blsPrivKey = ikm || mnemonic ? deriveBlsPrivateKey(mnemonic, ikm, perValidatorPath) : undefined;
89
87
  const blsPubCompressed = blsPrivKey ? await computeBlsPublicKeyCompressed(blsPrivKey) : undefined;
90
88
 
91
- if (blsOnly) {
92
- const attester = { bls: blsPrivKey! };
93
- summaries.push({ attesterBls: blsPubCompressed });
94
- return { attester, feeRecipient } as ValidatorKeyStore;
95
- }
96
-
97
89
  const ethAttester = deriveEthAttester(mnemonic, accountIndex, addressIndex, remoteSigner);
98
90
  const attester = blsPrivKey ? { eth: ethAttester, bls: blsPrivKey } : ethAttester;
99
91