@aztec-labs/cli 6.0.0-rc.1 → 6.0.0-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.
@@ -55,6 +55,8 @@ export declare const devnetConfig: {
55
55
  readonly SPONSORED_FPC: true;
56
56
  readonly TRANSACTIONS_DISABLED: false;
57
57
  readonly SEQ_MAX_TX_PER_BLOCK: 18;
58
+ readonly SEQ_MAX_TX_PER_CHECKPOINT: 36;
59
+ readonly VALIDATOR_MAX_TX_PER_CHECKPOINT: 72;
58
60
  readonly PROVER_REAL_PROOFS: false;
59
61
  readonly PXE_PROVER_ENABLED: false;
60
62
  readonly SYNC_SNAPSHOTS_URLS: "";
@@ -110,6 +112,8 @@ export declare const testnetConfig: {
110
112
  readonly SEQ_BLOCK_DURATION_MS: 6000;
111
113
  readonly MAX_BLOCKS_PER_CHECKPOINT: 10;
112
114
  readonly CHECKPOINT_PROPOSAL_SYNC_GRACE_SECONDS: 12;
115
+ readonly SEQ_MAX_TX_PER_CHECKPOINT: 72;
116
+ readonly VALIDATOR_MAX_TX_PER_CHECKPOINT: 144;
113
117
  readonly DATA_STORE_MAP_SIZE_KB: 134217728;
114
118
  readonly ARCHIVER_STORE_MAP_SIZE_KB: 1073741824;
115
119
  readonly NOTE_HASH_TREE_MAP_SIZE_KB: 1073741824;
@@ -136,7 +140,6 @@ export declare const testnetConfig: {
136
140
  readonly TEST_ACCOUNTS: false;
137
141
  readonly SPONSORED_FPC: false;
138
142
  readonly TRANSACTIONS_DISABLED: false;
139
- readonly SEQ_MAX_TX_PER_CHECKPOINT: 72;
140
143
  readonly PROVER_REAL_PROOFS: true;
141
144
  readonly P2P_MAX_PENDING_TX_COUNT: 1000;
142
145
  readonly P2P_TX_POOL_DELETE_TXS_AFTER_REORG: true;
@@ -177,6 +180,8 @@ export declare const mainnetConfig: {
177
180
  readonly SEQ_BLOCK_DURATION_MS: 6000;
178
181
  readonly MAX_BLOCKS_PER_CHECKPOINT: 10;
179
182
  readonly CHECKPOINT_PROPOSAL_SYNC_GRACE_SECONDS: 12;
183
+ readonly SEQ_MAX_TX_PER_CHECKPOINT: 72;
184
+ readonly VALIDATOR_MAX_TX_PER_CHECKPOINT: 144;
180
185
  readonly DATA_STORE_MAP_SIZE_KB: 134217728;
181
186
  readonly ARCHIVER_STORE_MAP_SIZE_KB: 1073741824;
182
187
  readonly NOTE_HASH_TREE_MAP_SIZE_KB: 1073741824;
@@ -211,7 +216,6 @@ export declare const mainnetConfig: {
211
216
  readonly TEST_ACCOUNTS: false;
212
217
  readonly SPONSORED_FPC: false;
213
218
  readonly TRANSACTIONS_DISABLED: false;
214
- readonly SEQ_MAX_TX_PER_CHECKPOINT: 72;
215
219
  readonly PROVER_REAL_PROOFS: true;
216
220
  readonly BLOB_ALLOW_EMPTY_SOURCES: true;
217
221
  readonly P2P_MAX_PENDING_TX_COUNT: 1000;
@@ -233,4 +237,4 @@ export declare const mainnetConfig: {
233
237
  readonly SLASH_INVALID_CHECKPOINT_PROPOSAL_PENALTY: 2e+21;
234
238
  readonly SLASH_GRACE_PERIOD_L2_SLOTS: 8400;
235
239
  };
236
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0d29ya3MuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb25maWcvZ2VuZXJhdGVkL25ldHdvcmtzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLGVBQU8sTUFBTSxZQUFZOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0FpRmYsQ0FBQztBQUVYLGVBQU8sTUFBTSxhQUFhOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztDQTBFaEIsQ0FBQztBQUVYLGVBQU8sTUFBTSxhQUFhOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztDQTZFaEIsQ0FBQyJ9
240
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0d29ya3MuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb25maWcvZ2VuZXJhdGVkL25ldHdvcmtzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLGVBQU8sTUFBTSxZQUFZOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztDQW1GZixDQUFDO0FBRVgsZUFBTyxNQUFNLGFBQWE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztDQTJFaEIsQ0FBQztBQUVYLGVBQU8sTUFBTSxhQUFhOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0E4RWhCLENBQUMifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"networks.d.ts","sourceRoot":"","sources":["../../../src/config/generated/networks.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiFf,CAAC;AAEX,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0EhB,CAAC;AAEX,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6EhB,CAAC"}
1
+ {"version":3,"file":"networks.d.ts","sourceRoot":"","sources":["../../../src/config/generated/networks.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFf,CAAC;AAEX,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2EhB,CAAC;AAEX,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8EhB,CAAC"}
@@ -57,6 +57,8 @@ export const devnetConfig = {
57
57
  SPONSORED_FPC: true,
58
58
  TRANSACTIONS_DISABLED: false,
59
59
  SEQ_MAX_TX_PER_BLOCK: 18,
60
+ SEQ_MAX_TX_PER_CHECKPOINT: 36,
61
+ VALIDATOR_MAX_TX_PER_CHECKPOINT: 72,
60
62
  PROVER_REAL_PROOFS: false,
61
63
  PXE_PROVER_ENABLED: false,
62
64
  SYNC_SNAPSHOTS_URLS: '',
@@ -112,6 +114,8 @@ export const testnetConfig = {
112
114
  SEQ_BLOCK_DURATION_MS: 6000,
113
115
  MAX_BLOCKS_PER_CHECKPOINT: 10,
114
116
  CHECKPOINT_PROPOSAL_SYNC_GRACE_SECONDS: 12,
117
+ SEQ_MAX_TX_PER_CHECKPOINT: 72,
118
+ VALIDATOR_MAX_TX_PER_CHECKPOINT: 144,
115
119
  DATA_STORE_MAP_SIZE_KB: 134217728,
116
120
  ARCHIVER_STORE_MAP_SIZE_KB: 1073741824,
117
121
  NOTE_HASH_TREE_MAP_SIZE_KB: 1073741824,
@@ -138,7 +142,6 @@ export const testnetConfig = {
138
142
  TEST_ACCOUNTS: false,
139
143
  SPONSORED_FPC: false,
140
144
  TRANSACTIONS_DISABLED: false,
141
- SEQ_MAX_TX_PER_CHECKPOINT: 72,
142
145
  PROVER_REAL_PROOFS: true,
143
146
  P2P_MAX_PENDING_TX_COUNT: 1000,
144
147
  P2P_TX_POOL_DELETE_TXS_AFTER_REORG: true,
@@ -179,6 +182,8 @@ export const mainnetConfig = {
179
182
  SEQ_BLOCK_DURATION_MS: 6000,
180
183
  MAX_BLOCKS_PER_CHECKPOINT: 10,
181
184
  CHECKPOINT_PROPOSAL_SYNC_GRACE_SECONDS: 12,
185
+ SEQ_MAX_TX_PER_CHECKPOINT: 72,
186
+ VALIDATOR_MAX_TX_PER_CHECKPOINT: 144,
182
187
  DATA_STORE_MAP_SIZE_KB: 134217728,
183
188
  ARCHIVER_STORE_MAP_SIZE_KB: 1073741824,
184
189
  NOTE_HASH_TREE_MAP_SIZE_KB: 1073741824,
@@ -213,7 +218,6 @@ export const mainnetConfig = {
213
218
  TEST_ACCOUNTS: false,
214
219
  SPONSORED_FPC: false,
215
220
  TRANSACTIONS_DISABLED: false,
216
- SEQ_MAX_TX_PER_CHECKPOINT: 72,
217
221
  PROVER_REAL_PROOFS: true,
218
222
  BLOB_ALLOW_EMPTY_SOURCES: true,
219
223
  P2P_MAX_PENDING_TX_COUNT: 1000,
@@ -1,5 +1,6 @@
1
1
  export * from './cached_fetch.js';
2
2
  export * from './chain_l2_config.js';
3
+ export * from './generated/networks.js';
3
4
  export * from './get_l1_config.js';
4
5
  export * from './network_config.js';
5
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb25maWcvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxxQkFBcUIsQ0FBQyJ9
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb25maWcvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxjQUFjLHFCQUFxQixDQUFDIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export * from './cached_fetch.js';
2
2
  export * from './chain_l2_config.js';
3
+ export * from './generated/networks.js';
3
4
  export * from './get_l1_config.js';
4
5
  export * from './network_config.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec-labs/cli",
3
- "version": "6.0.0-rc.1",
3
+ "version": "6.0.0-rc.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./devnet": "./dest/cmds/devnet/index.js",
@@ -76,19 +76,19 @@
76
76
  ]
77
77
  },
78
78
  "dependencies": {
79
- "@aztec-foundation/l1-artifacts": "6.0.0-rc.1",
80
- "@aztec-labs/accounts": "6.0.0-rc.1",
81
- "@aztec-labs/archiver": "6.0.0-rc.1",
82
- "@aztec-labs/aztec.js": "6.0.0-rc.1",
83
- "@aztec-labs/constants": "6.0.0-rc.1",
84
- "@aztec-labs/ethereum": "6.0.0-rc.1",
85
- "@aztec-labs/foundation": "6.0.0-rc.1",
86
- "@aztec-labs/node-keystore": "6.0.0-rc.1",
87
- "@aztec-labs/p2p": "6.0.0-rc.1",
88
- "@aztec-labs/protocol-contracts": "6.0.0-rc.1",
89
- "@aztec-labs/stdlib": "6.0.0-rc.1",
90
- "@aztec-labs/wallets": "6.0.0-rc.1",
91
- "@aztec-labs/world-state": "6.0.0-rc.1",
79
+ "@aztec-foundation/l1-artifacts": "6.0.0-rc.5",
80
+ "@aztec-labs/accounts": "6.0.0-rc.2",
81
+ "@aztec-labs/archiver": "6.0.0-rc.2",
82
+ "@aztec-labs/aztec.js": "6.0.0-rc.2",
83
+ "@aztec-labs/constants": "6.0.0-rc.2",
84
+ "@aztec-labs/ethereum": "6.0.0-rc.2",
85
+ "@aztec-labs/foundation": "6.0.0-rc.2",
86
+ "@aztec-labs/node-keystore": "6.0.0-rc.2",
87
+ "@aztec-labs/p2p": "6.0.0-rc.2",
88
+ "@aztec-labs/protocol-contracts": "6.0.0-rc.2",
89
+ "@aztec-labs/stdlib": "6.0.0-rc.2",
90
+ "@aztec-labs/wallets": "6.0.0-rc.2",
91
+ "@aztec-labs/world-state": "6.0.0-rc.2",
92
92
  "@ethersproject/wallet": "^5.8.0",
93
93
  "@iarna/toml": "^2.2.5",
94
94
  "@libp2p/peer-id-factory": "^3.0.4",
@@ -118,15 +118,15 @@
118
118
  "typescript": "^5.3.3"
119
119
  },
120
120
  "peerDependencies": {
121
- "@aztec-foundation/l1-artifacts": "6.0.0-rc.1",
122
- "@aztec-labs/accounts": "6.0.0-rc.1",
123
- "@aztec-labs/bb-prover": "6.0.0-rc.1",
124
- "@aztec-labs/ethereum": "6.0.0-rc.1",
125
- "@aztec-labs/noir-contracts.js": "6.0.0-rc.1",
126
- "@aztec-labs/noir-protocol-circuits-types": "6.0.0-rc.1",
127
- "@aztec-labs/noir-test-contracts.js": "6.0.0-rc.1",
128
- "@aztec-labs/protocol-contracts": "6.0.0-rc.1",
129
- "@aztec-labs/stdlib": "6.0.0-rc.1"
121
+ "@aztec-foundation/l1-artifacts": "6.0.0-rc.5",
122
+ "@aztec-labs/accounts": "6.0.0-rc.2",
123
+ "@aztec-labs/bb-prover": "6.0.0-rc.2",
124
+ "@aztec-labs/ethereum": "6.0.0-rc.2",
125
+ "@aztec-labs/noir-contracts.js": "6.0.0-rc.2",
126
+ "@aztec-labs/noir-protocol-circuits-types": "6.0.0-rc.2",
127
+ "@aztec-labs/noir-test-contracts.js": "6.0.0-rc.2",
128
+ "@aztec-labs/protocol-contracts": "6.0.0-rc.2",
129
+ "@aztec-labs/stdlib": "6.0.0-rc.2"
130
130
  },
131
131
  "files": [
132
132
  "dest",
@@ -11,6 +11,7 @@ import {
11
11
  nodeOption,
12
12
  parseBigint,
13
13
  parseEthereumAddress,
14
+ parseOptionalInteger,
14
15
  } from '../../utils/commands.js';
15
16
 
16
17
  const l1RpcUrlsOption = new Option(
@@ -312,6 +313,7 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger
312
313
  parseBigint,
313
314
  )
314
315
  .option('--move-with-latest-rollup', 'Whether to move with the latest rollup', true)
316
+ .option('--no-move-with-latest-rollup', 'Keep the stake on this rollup after an upgrade')
315
317
  .option('--rollup <string>', 'Rollup contract address', parseEthereumAddress)
316
318
  .action(async options => {
317
319
  const { addL1ValidatorViaRollup } = await import('./update_l1_validators.js');
@@ -337,13 +339,14 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger
337
339
  });
338
340
  });
339
341
 
340
- program
341
- .command('initiate-withdraw-by-attester')
342
- .description("Initiates a withdrawal signed by the position's attester.")
342
+ addSignerOptions(
343
+ program
344
+ .command('initiate-withdraw-by-attester')
345
+ .description("Initiates a withdrawal signed by the position's attester."),
346
+ 'attester',
347
+ )
343
348
  .addOption(l1RpcUrlsOption)
344
349
  .addOption(l1ChainIdOption)
345
- .option('-pk, --private-key <string>', 'The attester private key', PRIVATE_KEY)
346
- .option('-m, --mnemonic <string>', 'Mnemonic for the attester account', MNEMONIC)
347
350
  .requiredOption('--attester <address>', 'Attester address of the position to exit', parseEthereumAddress)
348
351
  .requiredOption('--rollup <address>', 'Rollup holding the position', parseEthereumAddress)
349
352
  .action(async options => {
@@ -353,6 +356,8 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger
353
356
  chainId: options.l1ChainId,
354
357
  privateKey: options.privateKey,
355
358
  mnemonic: options.mnemonic,
359
+ accountIndex: options.accountIndex,
360
+ addressIndex: options.addressIndex,
356
361
  attesterAddress: options.attester,
357
362
  rollupAddress: options.rollup,
358
363
  log,
@@ -360,19 +365,98 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger
360
365
  });
361
366
  });
362
367
 
363
- program
364
- .command('initiate-withdraw-by-attester-batch')
365
- .description('Relays a JSON array of attester-signed withdrawal authorizations.')
368
+ addSignerOptions(
369
+ program
370
+ .command('sign-attester-exit')
371
+ .description('Signs an exit authorization locally and writes a JSON array for batch submission.'),
372
+ 'attester',
373
+ )
374
+ .addOption(
375
+ new Option(
376
+ '--l1-rpc-urls <string>',
377
+ 'Ethereum host URLs (comma separated); when given, the chain ID they report must match, and they supply it or the rollup when those are not given',
378
+ )
379
+ .env('ETHEREUM_HOSTS')
380
+ .argParser((arg: string) => arg.split(',').map(url => url.trim())),
381
+ )
382
+ .addOption(
383
+ new Option(
384
+ '-c, --l1-chain-id <number>',
385
+ 'Chain ID to sign for; required unless --network or --l1-rpc-urls supplies it, and a value from L1_CHAIN_ID alone must be confirmed by one of them',
386
+ )
387
+ .env('L1_CHAIN_ID')
388
+ .argParser(Number),
389
+ )
390
+ .addOption(networkOption)
391
+ .requiredOption('--attester <address>', 'Attester address of the position to exit', parseEthereumAddress)
392
+ .option(
393
+ '--rollup <address>',
394
+ 'Rollup holding the position; defaults to the canonical rollup of --network',
395
+ parseEthereumAddress,
396
+ )
397
+ .requiredOption('--deadline <timestamp>', 'Authorization expiry as Unix seconds', parseBigint)
398
+ .requiredOption('--output <path>', 'JSON output file (must be new unless --append is used)')
399
+ .option(
400
+ '--append',
401
+ 'Append or create if missing, without validating existing authorizations; run initiate-withdraw-by-attester-batch --dry-run after the batch is complete',
402
+ )
403
+ .addHelpText(
404
+ 'after',
405
+ `
406
+ Examples:
407
+ aztec sign-attester-exit --private-key "$ATTESTER_KEY_0" --attester "$ATTESTER_0" --rollup "$ROLLUP" --l1-chain-id "$CHAIN_ID" --deadline "$DEADLINE" --output exits.json --append
408
+ aztec sign-attester-exit --private-key "$ATTESTER_KEY_1" --attester "$ATTESTER_1" --rollup "$ROLLUP" --l1-chain-id "$CHAIN_ID" --deadline "$DEADLINE" --output exits.json --append
409
+ aztec sign-attester-exit --mnemonic "$VALIDATOR_MNEMONIC" --account-index 0 --address-index 2 --attester "$ATTESTER_2" --rollup "$ROLLUP" --l1-chain-id "$CHAIN_ID" --deadline "$DEADLINE" --output exits.json --append
410
+ aztec sign-attester-exit --network testnet --l1-rpc-urls "$L1_RPC_URL" --private-key "$ATTESTER_KEY_3" --attester "$ATTESTER_3" --deadline "$DEADLINE" --output exits.json --append
411
+ aztec initiate-withdraw-by-attester-batch --dry-run --authorizations exits.json --rollup "$ROLLUP" --l1-chain-id "$CHAIN_ID" --l1-rpc-urls "$L1_RPC_URL"
412
+ aztec initiate-withdraw-by-attester-batch --authorizations exits.json --rollup "$ROLLUP" --l1-chain-id "$CHAIN_ID" --l1-rpc-urls "$L1_RPC_URL" --private-key "$RELAYER_PRIVATE_KEY"
413
+ Note: DEADLINE is a future Unix timestamp in seconds. Run append commands sequentially.
414
+ `,
415
+ )
416
+
417
+ .action(async (options, command: Command) => {
418
+ const { getAttesterExitNetwork, resolveAttesterExitTarget, signAttesterExit } = await import(
419
+ './update_l1_validators.js'
420
+ );
421
+ const { chainId, rollupAddress } = await resolveAttesterExitTarget({
422
+ chainId: options.l1ChainId,
423
+ chainIdFromEnv: command.getOptionValueSource('l1ChainId') === 'env',
424
+ rpcUrls: options.l1RpcUrls,
425
+ network: options.network ? await getAttesterExitNetwork(options.network) : undefined,
426
+ rollupAddress: options.rollup,
427
+ log,
428
+ });
429
+ await signAttesterExit({
430
+ rpcUrls: options.l1RpcUrls ?? [],
431
+ chainId,
432
+ privateKey: options.privateKey,
433
+ mnemonic: options.mnemonic,
434
+ accountIndex: options.accountIndex,
435
+ addressIndex: options.addressIndex,
436
+ attesterAddress: options.attester,
437
+ rollupAddress,
438
+ deadline: options.deadline,
439
+ output: options.output,
440
+ append: options.append,
441
+ log,
442
+ });
443
+ });
444
+
445
+ addSignerOptions(
446
+ program
447
+ .command('initiate-withdraw-by-attester-batch')
448
+ .description('Relays a JSON array of attester-signed withdrawal authorizations.'),
449
+ 'relayer',
450
+ )
366
451
  .addOption(l1RpcUrlsOption)
367
452
  .addOption(l1ChainIdOption)
368
- .option('-pk, --private-key <string>', 'The relayer private key', PRIVATE_KEY)
369
- .option('-m, --mnemonic <string>', 'Mnemonic for the relayer account', MNEMONIC)
370
453
  .requiredOption('--authorizations <path>', 'JSON file containing attester, decimal deadline, and signature fields')
371
454
  .requiredOption('--rollup <address>', 'Rollup holding the positions', parseEthereumAddress)
372
455
  .option(
373
456
  '--up-to-limit',
374
457
  'Process the largest permitted prefix instead of reverting when the whole batch is too large',
375
458
  )
459
+ .option('--dry-run', 'Simulate against current chain state without sending; no relayer key is required')
376
460
  .action(async options => {
377
461
  const { initiateWithdrawByAttesterBatch, readAttesterExitAuthorizations } = await import(
378
462
  './update_l1_validators.js'
@@ -382,8 +466,11 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger
382
466
  chainId: options.l1ChainId,
383
467
  privateKey: options.privateKey,
384
468
  mnemonic: options.mnemonic,
469
+ accountIndex: options.accountIndex,
470
+ addressIndex: options.addressIndex,
385
471
  authorizations: await readAttesterExitAuthorizations(options.authorizations),
386
472
  upToLimit: options.upToLimit,
473
+ dryRun: options.dryRun,
387
474
  rollupAddress: options.rollup,
388
475
  log,
389
476
  debugLogger,
@@ -550,3 +637,42 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger
550
637
 
551
638
  return program;
552
639
  }
640
+
641
+ function addSignerOptions(command: Command, role: 'attester' | 'relayer'): Command {
642
+ return command
643
+ .addOption(
644
+ new Option('-pk, --private-key <string>', `The ${role} private key; supply this or --mnemonic`).env(
645
+ 'PRIVATE_KEY',
646
+ ),
647
+ )
648
+ .addOption(
649
+ new Option(
650
+ '-m, --mnemonic <string>',
651
+ `Mnemonic for the ${role} account; a flag overrides the other credential from the environment, and PRIVATE_KEY wins when both come from the environment`,
652
+ ).env('MNEMONIC'),
653
+ )
654
+ .option(
655
+ '--account-index <number>',
656
+ 'Mnemonic account index, matching validator-keys generation (default: 0; requires --mnemonic)',
657
+ value => parseOptionalInteger(value, 0),
658
+ )
659
+ .option(
660
+ '--address-index <number>',
661
+ role === 'attester'
662
+ ? 'Mnemonic address index: validator-keys base address index + zero-based validator position; third validator = base + 2 (default: 0; requires --mnemonic)'
663
+ : 'Mnemonic address index for the relayer paying for the transaction; attesters sign authorizations separately (default: 0; requires --mnemonic)',
664
+ value => parseOptionalInteger(value, 0),
665
+ )
666
+ .hook('preAction', (_, actionCommand) => {
667
+ const { privateKey, mnemonic } = actionCommand.opts();
668
+ if (!privateKey || !mnemonic) {
669
+ return;
670
+ }
671
+ // Only two credentials passed as flags are a conflict; otherwise drop the one that came from the environment.
672
+ if (actionCommand.getOptionValueSource('mnemonic') === 'env') {
673
+ actionCommand.setOptionValue('mnemonic', undefined);
674
+ } else if (actionCommand.getOptionValueSource('privateKey') === 'env') {
675
+ actionCommand.setOptionValue('privateKey', undefined);
676
+ }
677
+ });
678
+ }
@@ -0,0 +1,43 @@
1
+ import type { EthAddress } from '@aztec-labs/foundation/eth-address';
2
+ import { createServer } from 'node:http';
3
+ import { encodeAbiParameters } from 'viem';
4
+
5
+ /**
6
+ * Starts a JSON-RPC server that reports `chainId` and, when `canonicalRollup` is given, answers every `eth_call` with
7
+ * that address and records the call. Any other method gets an error.
8
+ */
9
+ export async function serveL1Rpc(chainId: number, canonicalRollup?: EthAddress) {
10
+ const registryCalls: { to: string; data: string }[] = [];
11
+ const server = createServer((request, response) => {
12
+ let body = '';
13
+ request.on('data', chunk => (body += chunk));
14
+ request.on('end', () => {
15
+ const { id, method, params } = JSON.parse(body);
16
+ response.setHeader('content-type', 'application/json');
17
+ if (method === 'eth_chainId') {
18
+ response.end(JSON.stringify({ jsonrpc: '2.0', id, result: `0x${chainId.toString(16)}` }));
19
+ } else if (method === 'eth_call' && canonicalRollup) {
20
+ registryCalls.push({ to: params[0].to, data: params[0].data });
21
+ response.end(
22
+ JSON.stringify({
23
+ jsonrpc: '2.0',
24
+ id,
25
+ result: encodeAbiParameters([{ type: 'address' }], [canonicalRollup.toString() as `0x${string}`]),
26
+ }),
27
+ );
28
+ } else {
29
+ response.end(JSON.stringify({ jsonrpc: '2.0', id, error: { code: -32601, message: 'Unsupported method' } }));
30
+ }
31
+ });
32
+ });
33
+ await new Promise<void>(resolve => server.listen(0, '127.0.0.1', resolve));
34
+ const address = server.address();
35
+ if (!address || typeof address === 'string') {
36
+ throw new Error('Expected a TCP server address');
37
+ }
38
+ return {
39
+ url: `http://127.0.0.1:${address.port}`,
40
+ registryCalls,
41
+ close: () => new Promise(resolve => server.close(resolve)),
42
+ };
43
+ }