@aztec-labs/cli 6.0.0-nightly.20260918 → 6.0.0-nightly.20260920

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.
@@ -1,4 +1,10 @@
1
1
  import type { LogFn } from '@aztec-labs/foundation/log';
2
- /** Computes and prints genesis values needed for L1 contract deployment. */
2
+ /**
3
+ * Computes and prints genesis values needed for L1 contract deployment.
4
+ *
5
+ * `genesisArchiveRoot` is this deployment's root, which depends on the accounts it prefunds. The `canonical` block is
6
+ * the prefunding-free genesis that the `GENESIS_*` protocol constants record, and is what
7
+ * `noir-projects/fnd/scripts/regenerate_genesis_constants.sh` reads to refresh them.
8
+ */
3
9
  export declare function computeGenesisValuesCmd(testAccounts: boolean, sponsoredFPC: boolean, log: LogFn): Promise<void>;
4
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcHV0ZV9nZW5lc2lzX3ZhbHVlcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NtZHMvbDEvY29tcHV0ZV9nZW5lc2lzX3ZhbHVlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQU14RCw0RUFBNEU7QUFDNUUsd0JBQXNCLHVCQUF1QixDQUFDLFlBQVksRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsS0FBSyxpQkFvQnJHIn0=
10
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcHV0ZV9nZW5lc2lzX3ZhbHVlcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NtZHMvbDEvY29tcHV0ZV9nZW5lc2lzX3ZhbHVlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQU14RDs7Ozs7O0dBTUc7QUFDSCx3QkFBc0IsdUJBQXVCLENBQUMsWUFBWSxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxLQUFLLGlCQTJCckcifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"compute_genesis_values.d.ts","sourceRoot":"","sources":["../../../src/cmds/l1/compute_genesis_values.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAMxD,4EAA4E;AAC5E,wBAAsB,uBAAuB,CAAC,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,iBAoBrG"}
1
+ {"version":3,"file":"compute_genesis_values.d.ts","sourceRoot":"","sources":["../../../src/cmds/l1/compute_genesis_values.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAMxD;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAAC,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,iBA2BrG"}
@@ -1,17 +1,30 @@
1
1
  import { getInitialTestAccountsData } from '@aztec-labs/accounts/testing';
2
2
  import { protocolContractsHash } from '@aztec-labs/protocol-contracts';
3
- import { getGenesisValues } from '@aztec-labs/world-state/testing';
3
+ import { getGenesisValues, measureCanonicalGenesis } from '@aztec-labs/world-state/testing';
4
4
  import { getSponsoredFPCAddress } from '../../utils/setup_contracts.js';
5
- /** Computes and prints genesis values needed for L1 contract deployment. */ export async function computeGenesisValuesCmd(testAccounts, sponsoredFPC, log) {
5
+ /**
6
+ * Computes and prints genesis values needed for L1 contract deployment.
7
+ *
8
+ * `genesisArchiveRoot` is this deployment's root, which depends on the accounts it prefunds. The `canonical` block is
9
+ * the prefunding-free genesis that the `GENESIS_*` protocol constants record, and is what
10
+ * `noir-projects/fnd/scripts/regenerate_genesis_constants.sh` reads to refresh them.
11
+ */ export async function computeGenesisValuesCmd(testAccounts, sponsoredFPC, log) {
6
12
  const initialAccounts = testAccounts ? await getInitialTestAccountsData() : [];
7
13
  const sponsoredFPCAddresses = sponsoredFPC ? await getSponsoredFPCAddress() : [];
8
14
  const initialFundedAccounts = initialAccounts.map((a)=>a.address).concat(sponsoredFPCAddresses);
9
15
  const { genesisArchiveRoot } = await getGenesisValues(initialFundedAccounts);
16
+ const canonical = await measureCanonicalGenesis();
10
17
  const { getVKTreeRoot } = await import('@aztec-labs/noir-protocol-circuits-types/vk-tree');
11
18
  const vkTreeRoot = getVKTreeRoot();
12
19
  log(JSON.stringify({
13
20
  vkTreeRoot: vkTreeRoot.toString(),
14
21
  protocolContractsHash: protocolContractsHash.toString(),
15
- genesisArchiveRoot: genesisArchiveRoot.toString()
22
+ genesisArchiveRoot: genesisArchiveRoot.toString(),
23
+ canonical: {
24
+ prefilledNullifiers: canonical.prefilledNullifiers.map((n)=>n.toString()),
25
+ nullifierTreeRoot: canonical.nullifierTreeRoot.toString(),
26
+ blockHeaderHash: canonical.blockHeaderHash.toString(),
27
+ archiveRoot: canonical.archiveRoot.toString()
28
+ }
16
29
  }, null, 2));
17
30
  }
@@ -1,4 +1,4 @@
1
1
  import type { LogFn, Logger } from '@aztec-labs/foundation/log';
2
2
  import { type Command } from 'commander';
3
3
  export declare function injectCommands(program: Command, log: LogFn, debugLogger: Logger): Command;
4
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jbWRzL2wxL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsS0FBSyxPQUFPLEVBQVUsTUFBTSxXQUFXLENBQUM7QUF1QmpELHdCQUFnQixjQUFjLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLFdBd2QvRSJ9
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jbWRzL2wxL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsS0FBSyxPQUFPLEVBQVUsTUFBTSxXQUFXLENBQUM7QUF1QmpELHdCQUFnQixjQUFjLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLFdBNmdCL0UifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmds/l1/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,WAAW,CAAC;AAuBjD,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,WAwd/E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmds/l1/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,WAAW,CAAC;AAuBjD,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,WA6gB/E"}
@@ -120,6 +120,33 @@ export function injectCommands(program, log, debugLogger) {
120
120
  debugLogger
121
121
  });
122
122
  });
123
+ program.command('initiate-withdraw-by-attester').description("Initiates a withdrawal signed by the position's attester.").addOption(l1RpcUrlsOption).addOption(l1ChainIdOption).option('-pk, --private-key <string>', 'The attester private key', PRIVATE_KEY).option('-m, --mnemonic <string>', 'Mnemonic for the attester account', MNEMONIC).requiredOption('--attester <address>', 'Attester address of the position to exit', parseEthereumAddress).requiredOption('--rollup <address>', 'Rollup holding the position', parseEthereumAddress).action(async (options)=>{
124
+ const { initiateWithdrawByAttester } = await import('./update_l1_validators.js');
125
+ await initiateWithdrawByAttester({
126
+ rpcUrls: options.l1RpcUrls,
127
+ chainId: options.l1ChainId,
128
+ privateKey: options.privateKey,
129
+ mnemonic: options.mnemonic,
130
+ attesterAddress: options.attester,
131
+ rollupAddress: options.rollup,
132
+ log,
133
+ debugLogger
134
+ });
135
+ });
136
+ program.command('initiate-withdraw-by-attester-batch').description('Relays a JSON array of attester-signed withdrawal authorizations.').addOption(l1RpcUrlsOption).addOption(l1ChainIdOption).option('-pk, --private-key <string>', 'The relayer private key', PRIVATE_KEY).option('-m, --mnemonic <string>', 'Mnemonic for the relayer account', MNEMONIC).requiredOption('--authorizations <path>', 'JSON file containing attester, decimal deadline, and signature fields').requiredOption('--rollup <address>', 'Rollup holding the positions', parseEthereumAddress).option('--up-to-limit', 'Process the largest permitted prefix instead of reverting when the whole batch is too large').action(async (options)=>{
137
+ const { initiateWithdrawByAttesterBatch, readAttesterExitAuthorizations } = await import('./update_l1_validators.js');
138
+ await initiateWithdrawByAttesterBatch({
139
+ rpcUrls: options.l1RpcUrls,
140
+ chainId: options.l1ChainId,
141
+ privateKey: options.privateKey,
142
+ mnemonic: options.mnemonic,
143
+ authorizations: await readAttesterExitAuthorizations(options.authorizations),
144
+ upToLimit: options.upToLimit,
145
+ rollupAddress: options.rollup,
146
+ log,
147
+ debugLogger
148
+ });
149
+ });
123
150
  program.command('remove-l1-validator').description('Removes a validator to the L1 rollup contract.').addOption(l1RpcUrlsOption).option('-pk, --private-key <string>', 'The private key to use for deployment', PRIVATE_KEY).option('-m, --mnemonic <string>', 'The mnemonic to use in deployment', 'test test test test test test test test test test test junk').addOption(l1ChainIdOption).option('--validator <address>', 'ethereum address of the validator', parseEthereumAddress).option('--rollup <address>', 'ethereum address of the rollup contract', parseEthereumAddress).action(async (options)=>{
124
151
  const { removeL1Validator } = await import('./update_l1_validators.js');
125
152
  await removeL1Validator({
@@ -1,4 +1,5 @@
1
- import type { EthAddress } from '@aztec-labs/foundation/eth-address';
1
+ import { type AttesterExitAuthorization } from '@aztec-labs/ethereum/contracts';
2
+ import { EthAddress } from '@aztec-labs/foundation/eth-address';
2
3
  import type { LogFn, Logger } from '@aztec-labs/foundation/log';
3
4
  export interface RollupCommandArgs {
4
5
  rpcUrls: string[];
@@ -37,9 +38,20 @@ export declare function addL1ValidatorViaRollup({ rpcUrls, chainId, privateKey,
37
38
  export declare function removeL1Validator({ rpcUrls, chainId, privateKey, mnemonic, validatorAddress, rollupAddress, log, debugLogger }: RollupCommandArgs & LoggerArgs & {
38
39
  validatorAddress: EthAddress;
39
40
  }): Promise<void>;
41
+ /** Reads relayed attester exit authorizations from a JSON array. */
42
+ export declare function readAttesterExitAuthorizations(path: string): Promise<AttesterExitAuthorization[]>;
43
+ /** Relays a batch of attester-signed exits. */
44
+ export declare function initiateWithdrawByAttesterBatch({ rpcUrls, chainId, privateKey, mnemonic, authorizations, upToLimit, rollupAddress, log, debugLogger }: Omit<RollupCommandArgs, 'withdrawerAddress'> & LoggerArgs & {
45
+ authorizations: AttesterExitAuthorization[];
46
+ upToLimit: boolean;
47
+ }): Promise<import("viem").TransactionReceipt>;
48
+ /** Initiates an attester exit without changing the registered withdrawer's control over the payout. */
49
+ export declare function initiateWithdrawByAttester({ rpcUrls, chainId, privateKey, mnemonic, attesterAddress, rollupAddress, log, debugLogger }: Omit<RollupCommandArgs, 'withdrawerAddress'> & LoggerArgs & {
50
+ attesterAddress: EthAddress;
51
+ }): Promise<import("viem").TransactionReceipt>;
40
52
  export declare function pruneRollup({ rpcUrls, chainId, privateKey, mnemonic, rollupAddress, log, debugLogger }: RollupCommandArgs & LoggerArgs): Promise<void>;
41
53
  export declare function fastForwardEpochs({ rpcUrls, chainId, rollupAddress, numEpochs, log, debugLogger }: RollupCommandArgs & LoggerArgs & {
42
54
  numEpochs: bigint;
43
55
  }): Promise<void>;
44
56
  export declare function debugRollup({ rpcUrls, chainId, rollupAddress, log }: RollupCommandArgs & LoggerArgs): Promise<void>;
45
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlX2wxX3ZhbGlkYXRvcnMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jbWRzL2wxL3VwZGF0ZV9sMV92YWxpZGF0b3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3JFLE9BQU8sS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQU1oRSxNQUFNLFdBQVcsaUJBQWlCO0lBQ2hDLE9BQU8sRUFBRSxNQUFNLEVBQUUsQ0FBQztJQUNsQixPQUFPLEVBQUUsTUFBTSxDQUFDO0lBQ2hCLFVBQVUsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNwQixRQUFRLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDbEIsYUFBYSxFQUFFLFVBQVUsQ0FBQztJQUMxQixpQkFBaUIsQ0FBQyxFQUFFLFVBQVUsQ0FBQztDQUNoQztBQUVELE1BQU0sV0FBVyw4QkFBOEI7SUFDN0MsT0FBTyxFQUFFLE1BQU0sRUFBRSxDQUFDO0lBQ2xCLE9BQU8sRUFBRSxNQUFNLENBQUM7SUFDaEIsVUFBVSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3BCLFFBQVEsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNsQiwwQkFBMEIsRUFBRSxVQUFVLENBQUM7Q0FDeEM7QUFFRCxNQUFNLFdBQVcsVUFBVTtJQUN6QixHQUFHLEVBQUUsS0FBSyxDQUFDO0lBQ1gsV0FBVyxFQUFFLE1BQU0sQ0FBQztDQUNyQjtBQUVELHdCQUFnQixpQkFBaUI7OztFQU9oQztBQUVELHdCQUFzQixjQUFjLENBQUMsRUFDbkMsT0FBTyxFQUNQLE9BQU8sRUFDUCxVQUFVLEVBQ1YsUUFBUSxFQUNSLGVBQWUsRUFDZixpQkFBaUIsRUFDakIsMEJBQTBCLEVBQzFCLFdBQVcsRUFDWCxZQUFZLEVBQ1osR0FBRyxFQUNILFdBQVcsRUFDWixFQUFFLDhCQUE4QixHQUMvQixVQUFVLEdBQUc7SUFDWCxZQUFZLEVBQUUsTUFBTSxDQUFDO0lBQ3JCLGVBQWUsRUFBRSxVQUFVLENBQUM7SUFDNUIsaUJBQWlCLEVBQUUsVUFBVSxDQUFDO0lBQzlCLFdBQVcsRUFBRSxNQUFNLENBQUM7Q0FDckIsaUJBd0ZGO0FBRUQsd0JBQXNCLHVCQUF1QixDQUFDLEVBQzVDLE9BQU8sRUFDUCxPQUFPLEVBQ1AsVUFBVSxFQUNWLFFBQVEsRUFDUixlQUFlLEVBQ2YsaUJBQWlCLEVBQ2pCLFlBQVksRUFDWixvQkFBb0IsRUFDcEIsYUFBYSxFQUNiLEdBQUcsRUFDSCxXQUFXLEVBQ1osRUFBRSxpQkFBaUIsR0FDbEIsVUFBVSxHQUFHO0lBQ1gsWUFBWSxFQUFFLE1BQU0sQ0FBQztJQUNyQixlQUFlLEVBQUUsVUFBVSxDQUFDO0lBQzVCLG9CQUFvQixFQUFFLE9BQU8sQ0FBQztDQUMvQixpQkF1REY7QUFFRCx3QkFBc0IsaUJBQWlCLENBQUMsRUFDdEMsT0FBTyxFQUNQLE9BQU8sRUFDUCxVQUFVLEVBQ1YsUUFBUSxFQUNSLGdCQUFnQixFQUNoQixhQUFhLEVBQ2IsR0FBRyxFQUNILFdBQVcsRUFDWixFQUFFLGlCQUFpQixHQUFHLFVBQVUsR0FBRztJQUFFLGdCQUFnQixFQUFFLFVBQVUsQ0FBQTtDQUFFLGlCQWlCbkU7QUFFRCx3QkFBc0IsV0FBVyxDQUFDLEVBQ2hDLE9BQU8sRUFDUCxPQUFPLEVBQ1AsVUFBVSxFQUNWLFFBQVEsRUFDUixhQUFhLEVBQ2IsR0FBRyxFQUNILFdBQVcsRUFDWixFQUFFLGlCQUFpQixHQUFHLFVBQVUsaUJBZ0JoQztBQUVELHdCQUFzQixpQkFBaUIsQ0FBQyxFQUN0QyxPQUFPLEVBQ1AsT0FBTyxFQUNQLGFBQWEsRUFDYixTQUFTLEVBQ1QsR0FBRyxFQUNILFdBQVcsRUFDWixFQUFFLGlCQUFpQixHQUFHLFVBQVUsR0FBRztJQUFFLFNBQVMsRUFBRSxNQUFNLENBQUE7Q0FBRSxpQkF5QnhEO0FBRUQsd0JBQXNCLFdBQVcsQ0FBQyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsYUFBYSxFQUFFLEdBQUcsRUFBRSxFQUFFLGlCQUFpQixHQUFHLFVBQVUsaUJBd0J6RyJ9
57
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlX2wxX3ZhbGlkYXRvcnMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jbWRzL2wxL3VwZGF0ZV9sMV92YWxpZGF0b3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUtBLE9BQU8sRUFBRSxLQUFLLHlCQUF5QixFQUErQixNQUFNLGdDQUFnQyxDQUFDO0FBRzdHLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUVoRSxPQUFPLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFPaEUsTUFBTSxXQUFXLGlCQUFpQjtJQUNoQyxPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUM7SUFDbEIsT0FBTyxFQUFFLE1BQU0sQ0FBQztJQUNoQixVQUFVLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDcEIsUUFBUSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2xCLGFBQWEsRUFBRSxVQUFVLENBQUM7SUFDMUIsaUJBQWlCLENBQUMsRUFBRSxVQUFVLENBQUM7Q0FDaEM7QUFFRCxNQUFNLFdBQVcsOEJBQThCO0lBQzdDLE9BQU8sRUFBRSxNQUFNLEVBQUUsQ0FBQztJQUNsQixPQUFPLEVBQUUsTUFBTSxDQUFDO0lBQ2hCLFVBQVUsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNwQixRQUFRLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDbEIsMEJBQTBCLEVBQUUsVUFBVSxDQUFDO0NBQ3hDO0FBRUQsTUFBTSxXQUFXLFVBQVU7SUFDekIsR0FBRyxFQUFFLEtBQUssQ0FBQztJQUNYLFdBQVcsRUFBRSxNQUFNLENBQUM7Q0FDckI7QUFFRCx3QkFBZ0IsaUJBQWlCOzs7RUFPaEM7QUFFRCx3QkFBc0IsY0FBYyxDQUFDLEVBQ25DLE9BQU8sRUFDUCxPQUFPLEVBQ1AsVUFBVSxFQUNWLFFBQVEsRUFDUixlQUFlLEVBQ2YsaUJBQWlCLEVBQ2pCLDBCQUEwQixFQUMxQixXQUFXLEVBQ1gsWUFB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
@@ -1 +1 @@
1
- {"version":3,"file":"update_l1_validators.d.ts","sourceRoot":"","sources":["../../../src/cmds/l1/update_l1_validators.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAMhE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,UAAU,CAAC;IAC1B,iBAAiB,CAAC,EAAE,UAAU,CAAC;CAChC;AAED,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0BAA0B,EAAE,UAAU,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,KAAK,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,iBAAiB;;;EAOhC;AAED,wBAAsB,cAAc,CAAC,EACnC,OAAO,EACP,OAAO,EACP,UAAU,EACV,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,0BAA0B,EAC1B,WAAW,EACX,YAAY,EACZ,GAAG,EACH,WAAW,EACZ,EAAE,8BAA8B,GAC/B,UAAU,GAAG;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,UAAU,CAAC;IAC5B,iBAAiB,EAAE,UAAU,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;CACrB,iBAwFF;AAED,wBAAsB,uBAAuB,CAAC,EAC5C,OAAO,EACP,OAAO,EACP,UAAU,EACV,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,aAAa,EACb,GAAG,EACH,WAAW,EACZ,EAAE,iBAAiB,GAClB,UAAU,GAAG;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,UAAU,CAAC;IAC5B,oBAAoB,EAAE,OAAO,CAAC;CAC/B,iBAuDF;AAED,wBAAsB,iBAAiB,CAAC,EACtC,OAAO,EACP,OAAO,EACP,UAAU,EACV,QAAQ,EACR,gBAAgB,EAChB,aAAa,EACb,GAAG,EACH,WAAW,EACZ,EAAE,iBAAiB,GAAG,UAAU,GAAG;IAAE,gBAAgB,EAAE,UAAU,CAAA;CAAE,iBAiBnE;AAED,wBAAsB,WAAW,CAAC,EAChC,OAAO,EACP,OAAO,EACP,UAAU,EACV,QAAQ,EACR,aAAa,EACb,GAAG,EACH,WAAW,EACZ,EAAE,iBAAiB,GAAG,UAAU,iBAgBhC;AAED,wBAAsB,iBAAiB,CAAC,EACtC,OAAO,EACP,OAAO,EACP,aAAa,EACb,SAAS,EACT,GAAG,EACH,WAAW,EACZ,EAAE,iBAAiB,GAAG,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,iBAyBxD;AAED,wBAAsB,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,EAAE,iBAAiB,GAAG,UAAU,iBAwBzG"}
1
+ {"version":3,"file":"update_l1_validators.d.ts","sourceRoot":"","sources":["../../../src/cmds/l1/update_l1_validators.ts"],"names":[],"mappings":"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"}
@@ -5,9 +5,12 @@ import { getL1ContractsConfigEnvVars } from '@aztec-labs/ethereum/config';
5
5
  import { GSEContract, RollupContract } from '@aztec-labs/ethereum/contracts';
6
6
  import { createL1TxUtils } from '@aztec-labs/ethereum/l1-tx-utils';
7
7
  import { EthCheatCodes } from '@aztec-labs/ethereum/test';
8
+ import { EthAddress } from '@aztec-labs/foundation/eth-address';
9
+ import { Signature } from '@aztec-labs/foundation/eth-signature';
8
10
  import { DateProvider } from '@aztec-labs/foundation/timer';
9
11
  import { ZkPassportProofParams } from '@aztec-labs/stdlib/zkpassport';
10
- import { encodeFunctionData, formatEther, getContract, maxUint256 } from 'viem';
12
+ import { readFile } from 'node:fs/promises';
13
+ import { encodeFunctionData, formatEther, getContract, isHex, maxUint256 } from 'viem';
11
14
  import { generatePrivateKey, mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
12
15
  export function generateL1Account() {
13
16
  const privateKey = generatePrivateKey();
@@ -188,6 +191,84 @@ export async function removeL1Validator({ rpcUrls, chainId, privateKey, mnemonic
188
191
  });
189
192
  dualLog(`Transaction hash: ${receipt.transactionHash}`);
190
193
  }
194
+ /** Reads relayed attester exit authorizations from a JSON array. */ export async function readAttesterExitAuthorizations(path) {
195
+ const parsed = JSON.parse(await readFile(path, 'utf-8'));
196
+ if (!Array.isArray(parsed) || parsed.length === 0) {
197
+ throw new Error('Attester exit authorization file must contain a non-empty JSON array');
198
+ }
199
+ return parsed.map((value, index)=>parseAttesterExitAuthorization(value, index));
200
+ }
201
+ function isRecord(value) {
202
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
203
+ }
204
+ function parseAttesterExitAuthorization(value, index) {
205
+ if (!isRecord(value)) {
206
+ throw new Error(`Attester exit authorization ${index} must be an object`);
207
+ }
208
+ const authorization = value;
209
+ if (typeof authorization.attester !== 'string') {
210
+ throw new Error(`Attester exit authorization ${index} has an invalid attester`);
211
+ }
212
+ if (typeof authorization.deadline !== 'string' || !/^\d+$/.test(authorization.deadline)) {
213
+ throw new Error(`Attester exit authorization ${index} deadline must be a decimal string`);
214
+ }
215
+ if (typeof authorization.signature !== 'string' || !isHex(authorization.signature)) {
216
+ throw new Error(`Attester exit authorization ${index} has an invalid signature`);
217
+ }
218
+ return {
219
+ attester: EthAddress.fromString(authorization.attester),
220
+ deadline: BigInt(authorization.deadline),
221
+ signature: Signature.fromString(authorization.signature).toViemSignature()
222
+ };
223
+ }
224
+ /** Relays a batch of attester-signed exits. */ export async function initiateWithdrawByAttesterBatch({ rpcUrls, chainId, privateKey, mnemonic, authorizations, upToLimit, rollupAddress, log, debugLogger }) {
225
+ const account = getAccount(privateKey, mnemonic);
226
+ const chain = createEthereumChain(rpcUrls, chainId);
227
+ const client = createExtendedL1Client(rpcUrls, account, chain.chainInfo);
228
+ const rollup = new RollupContract(client, rollupAddress);
229
+ const l1TxUtils = createL1TxUtils(client, {
230
+ logger: debugLogger
231
+ });
232
+ const { receipt } = upToLimit ? await rollup.initiateWithdrawByAttesterBatchUpToLimit(l1TxUtils, authorizations) : await rollup.initiateWithdrawByAttesterBatch(l1TxUtils, authorizations);
233
+ if (receipt.status !== 'success') {
234
+ throw new Error(`Attester exit batch reverted: ${receipt.transactionHash}`);
235
+ }
236
+ log(`Submitted ${authorizations.length} attester exit authorizations. Transaction hash: ${receipt.transactionHash}`);
237
+ if (upToLimit) {
238
+ log('The rollup processed the largest permitted prefix of the authorization list.');
239
+ }
240
+ debugLogger.info('Attester exit batch submitted', {
241
+ authorizationCount: authorizations.length,
242
+ upToLimit,
243
+ rollup: rollupAddress.toString(),
244
+ transactionHash: receipt.transactionHash
245
+ });
246
+ return receipt;
247
+ }
248
+ /** Initiates an attester exit without changing the registered withdrawer's control over the payout. */ export async function initiateWithdrawByAttester({ rpcUrls, chainId, privateKey, mnemonic, attesterAddress, rollupAddress, log, debugLogger }) {
249
+ const account = getAccount(privateKey, mnemonic);
250
+ if (account.address.toLowerCase() !== attesterAddress.toString().toLowerCase()) {
251
+ throw new Error('The transaction signer must match the attester address');
252
+ }
253
+ const chain = createEthereumChain(rpcUrls, chainId);
254
+ const client = createExtendedL1Client(rpcUrls, account, chain.chainInfo);
255
+ const rollup = new RollupContract(client, rollupAddress);
256
+ const l1TxUtils = createL1TxUtils(client, {
257
+ logger: debugLogger
258
+ });
259
+ const { receipt } = await rollup.initiateWithdrawByAttester(l1TxUtils, attesterAddress);
260
+ if (receipt.status !== 'success') {
261
+ throw new Error(`Attester exit reverted: ${receipt.transactionHash}`);
262
+ }
263
+ log(`Attester exit initiated for ${attesterAddress}. Transaction hash: ${receipt.transactionHash}`);
264
+ log('The registered withdrawer must select a recipient using initiateWithdraw before finalization.');
265
+ debugLogger.info('Attester exit initiated', {
266
+ attester: attesterAddress.toString(),
267
+ rollup: rollupAddress.toString(),
268
+ transactionHash: receipt.transactionHash
269
+ });
270
+ return receipt;
271
+ }
191
272
  export async function pruneRollup({ rpcUrls, chainId, privateKey, mnemonic, rollupAddress, log, debugLogger }) {
192
273
  const dualLog = makeDualLog(log, debugLogger);
193
274
  const account = getAccount(privateKey, mnemonic);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec-labs/cli",
3
- "version": "6.0.0-nightly.20260918",
3
+ "version": "6.0.0-nightly.20260920",
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-nightly.20260916",
80
- "@aztec-labs/accounts": "6.0.0-nightly.20260918",
81
- "@aztec-labs/archiver": "6.0.0-nightly.20260918",
82
- "@aztec-labs/aztec.js": "6.0.0-nightly.20260918",
83
- "@aztec-labs/constants": "6.0.0-nightly.20260918",
84
- "@aztec-labs/ethereum": "6.0.0-nightly.20260918",
85
- "@aztec-labs/foundation": "6.0.0-nightly.20260918",
86
- "@aztec-labs/node-keystore": "6.0.0-nightly.20260918",
87
- "@aztec-labs/p2p": "6.0.0-nightly.20260918",
88
- "@aztec-labs/protocol-contracts": "6.0.0-nightly.20260918",
89
- "@aztec-labs/stdlib": "6.0.0-nightly.20260918",
90
- "@aztec-labs/wallets": "6.0.0-nightly.20260918",
91
- "@aztec-labs/world-state": "6.0.0-nightly.20260918",
79
+ "@aztec-foundation/l1-artifacts": "6.0.0-nightly.20260918.a",
80
+ "@aztec-labs/accounts": "6.0.0-nightly.20260920",
81
+ "@aztec-labs/archiver": "6.0.0-nightly.20260920",
82
+ "@aztec-labs/aztec.js": "6.0.0-nightly.20260920",
83
+ "@aztec-labs/constants": "6.0.0-nightly.20260920",
84
+ "@aztec-labs/ethereum": "6.0.0-nightly.20260920",
85
+ "@aztec-labs/foundation": "6.0.0-nightly.20260920",
86
+ "@aztec-labs/node-keystore": "6.0.0-nightly.20260920",
87
+ "@aztec-labs/p2p": "6.0.0-nightly.20260920",
88
+ "@aztec-labs/protocol-contracts": "6.0.0-nightly.20260920",
89
+ "@aztec-labs/stdlib": "6.0.0-nightly.20260920",
90
+ "@aztec-labs/wallets": "6.0.0-nightly.20260920",
91
+ "@aztec-labs/world-state": "6.0.0-nightly.20260920",
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-nightly.20260916",
122
- "@aztec-labs/accounts": "6.0.0-nightly.20260918",
123
- "@aztec-labs/bb-prover": "6.0.0-nightly.20260918",
124
- "@aztec-labs/ethereum": "6.0.0-nightly.20260918",
125
- "@aztec-labs/noir-contracts.js": "6.0.0-nightly.20260918",
126
- "@aztec-labs/noir-protocol-circuits-types": "6.0.0-nightly.20260918",
127
- "@aztec-labs/noir-test-contracts.js": "6.0.0-nightly.20260918",
128
- "@aztec-labs/protocol-contracts": "6.0.0-nightly.20260918",
129
- "@aztec-labs/stdlib": "6.0.0-nightly.20260918"
121
+ "@aztec-foundation/l1-artifacts": "6.0.0-nightly.20260918.a",
122
+ "@aztec-labs/accounts": "6.0.0-nightly.20260920",
123
+ "@aztec-labs/bb-prover": "6.0.0-nightly.20260920",
124
+ "@aztec-labs/ethereum": "6.0.0-nightly.20260920",
125
+ "@aztec-labs/noir-contracts.js": "6.0.0-nightly.20260920",
126
+ "@aztec-labs/noir-protocol-circuits-types": "6.0.0-nightly.20260920",
127
+ "@aztec-labs/noir-test-contracts.js": "6.0.0-nightly.20260920",
128
+ "@aztec-labs/protocol-contracts": "6.0.0-nightly.20260920",
129
+ "@aztec-labs/stdlib": "6.0.0-nightly.20260920"
130
130
  },
131
131
  "files": [
132
132
  "dest",
@@ -1,16 +1,23 @@
1
1
  import { getInitialTestAccountsData } from '@aztec-labs/accounts/testing';
2
2
  import type { LogFn } from '@aztec-labs/foundation/log';
3
3
  import { protocolContractsHash } from '@aztec-labs/protocol-contracts';
4
- import { getGenesisValues } from '@aztec-labs/world-state/testing';
4
+ import { getGenesisValues, measureCanonicalGenesis } from '@aztec-labs/world-state/testing';
5
5
 
6
6
  import { getSponsoredFPCAddress } from '../../utils/setup_contracts.js';
7
7
 
8
- /** Computes and prints genesis values needed for L1 contract deployment. */
8
+ /**
9
+ * Computes and prints genesis values needed for L1 contract deployment.
10
+ *
11
+ * `genesisArchiveRoot` is this deployment's root, which depends on the accounts it prefunds. The `canonical` block is
12
+ * the prefunding-free genesis that the `GENESIS_*` protocol constants record, and is what
13
+ * `noir-projects/fnd/scripts/regenerate_genesis_constants.sh` reads to refresh them.
14
+ */
9
15
  export async function computeGenesisValuesCmd(testAccounts: boolean, sponsoredFPC: boolean, log: LogFn) {
10
16
  const initialAccounts = testAccounts ? await getInitialTestAccountsData() : [];
11
17
  const sponsoredFPCAddresses = sponsoredFPC ? await getSponsoredFPCAddress() : [];
12
18
  const initialFundedAccounts = initialAccounts.map(a => a.address).concat(sponsoredFPCAddresses);
13
19
  const { genesisArchiveRoot } = await getGenesisValues(initialFundedAccounts);
20
+ const canonical = await measureCanonicalGenesis();
14
21
 
15
22
  const { getVKTreeRoot } = await import('@aztec-labs/noir-protocol-circuits-types/vk-tree');
16
23
  const vkTreeRoot = getVKTreeRoot();
@@ -21,6 +28,12 @@ export async function computeGenesisValuesCmd(testAccounts: boolean, sponsoredFP
21
28
  vkTreeRoot: vkTreeRoot.toString(),
22
29
  protocolContractsHash: protocolContractsHash.toString(),
23
30
  genesisArchiveRoot: genesisArchiveRoot.toString(),
31
+ canonical: {
32
+ prefilledNullifiers: canonical.prefilledNullifiers.map(n => n.toString()),
33
+ nullifierTreeRoot: canonical.nullifierTreeRoot.toString(),
34
+ blockHeaderHash: canonical.blockHeaderHash.toString(),
35
+ archiveRoot: canonical.archiveRoot.toString(),
36
+ },
24
37
  },
25
38
  null,
26
39
  2,
@@ -337,6 +337,59 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger
337
337
  });
338
338
  });
339
339
 
340
+ program
341
+ .command('initiate-withdraw-by-attester')
342
+ .description("Initiates a withdrawal signed by the position's attester.")
343
+ .addOption(l1RpcUrlsOption)
344
+ .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
+ .requiredOption('--attester <address>', 'Attester address of the position to exit', parseEthereumAddress)
348
+ .requiredOption('--rollup <address>', 'Rollup holding the position', parseEthereumAddress)
349
+ .action(async options => {
350
+ const { initiateWithdrawByAttester } = await import('./update_l1_validators.js');
351
+ await initiateWithdrawByAttester({
352
+ rpcUrls: options.l1RpcUrls,
353
+ chainId: options.l1ChainId,
354
+ privateKey: options.privateKey,
355
+ mnemonic: options.mnemonic,
356
+ attesterAddress: options.attester,
357
+ rollupAddress: options.rollup,
358
+ log,
359
+ debugLogger,
360
+ });
361
+ });
362
+
363
+ program
364
+ .command('initiate-withdraw-by-attester-batch')
365
+ .description('Relays a JSON array of attester-signed withdrawal authorizations.')
366
+ .addOption(l1RpcUrlsOption)
367
+ .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
+ .requiredOption('--authorizations <path>', 'JSON file containing attester, decimal deadline, and signature fields')
371
+ .requiredOption('--rollup <address>', 'Rollup holding the positions', parseEthereumAddress)
372
+ .option(
373
+ '--up-to-limit',
374
+ 'Process the largest permitted prefix instead of reverting when the whole batch is too large',
375
+ )
376
+ .action(async options => {
377
+ const { initiateWithdrawByAttesterBatch, readAttesterExitAuthorizations } = await import(
378
+ './update_l1_validators.js'
379
+ );
380
+ await initiateWithdrawByAttesterBatch({
381
+ rpcUrls: options.l1RpcUrls,
382
+ chainId: options.l1ChainId,
383
+ privateKey: options.privateKey,
384
+ mnemonic: options.mnemonic,
385
+ authorizations: await readAttesterExitAuthorizations(options.authorizations),
386
+ upToLimit: options.upToLimit,
387
+ rollupAddress: options.rollup,
388
+ log,
389
+ debugLogger,
390
+ });
391
+ });
392
+
340
393
  program
341
394
  .command('remove-l1-validator')
342
395
  .description('Removes a validator to the L1 rollup contract.')
@@ -3,14 +3,16 @@ import { RollupAbi, StakingAssetHandlerAbi, TestERC20Abi } from '@aztec-foundati
3
3
  import { createEthereumChain, isAnvilTestChain } from '@aztec-labs/ethereum/chain';
4
4
  import { createExtendedL1Client, getPublicClient } from '@aztec-labs/ethereum/client';
5
5
  import { getL1ContractsConfigEnvVars } from '@aztec-labs/ethereum/config';
6
- import { GSEContract, RollupContract } from '@aztec-labs/ethereum/contracts';
6
+ import { type AttesterExitAuthorization, GSEContract, RollupContract } from '@aztec-labs/ethereum/contracts';
7
7
  import { createL1TxUtils } from '@aztec-labs/ethereum/l1-tx-utils';
8
8
  import { EthCheatCodes } from '@aztec-labs/ethereum/test';
9
- import type { EthAddress } from '@aztec-labs/foundation/eth-address';
9
+ import { EthAddress } from '@aztec-labs/foundation/eth-address';
10
+ import { Signature } from '@aztec-labs/foundation/eth-signature';
10
11
  import type { LogFn, Logger } from '@aztec-labs/foundation/log';
11
12
  import { DateProvider } from '@aztec-labs/foundation/timer';
12
13
  import { ZkPassportProofParams } from '@aztec-labs/stdlib/zkpassport';
13
- import { encodeFunctionData, formatEther, getContract, maxUint256 } from 'viem';
14
+ import { readFile } from 'node:fs/promises';
15
+ import { encodeFunctionData, formatEther, getContract, isHex, maxUint256 } from 'viem';
14
16
  import { generatePrivateKey, mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
15
17
 
16
18
  export interface RollupCommandArgs {
@@ -254,6 +256,118 @@ export async function removeL1Validator({
254
256
  dualLog(`Transaction hash: ${receipt.transactionHash}`);
255
257
  }
256
258
 
259
+ /** Reads relayed attester exit authorizations from a JSON array. */
260
+ export async function readAttesterExitAuthorizations(path: string): Promise<AttesterExitAuthorization[]> {
261
+ const parsed: unknown = JSON.parse(await readFile(path, 'utf-8'));
262
+ if (!Array.isArray(parsed) || parsed.length === 0) {
263
+ throw new Error('Attester exit authorization file must contain a non-empty JSON array');
264
+ }
265
+
266
+ return parsed.map((value, index) => parseAttesterExitAuthorization(value, index));
267
+ }
268
+
269
+ function isRecord(value: unknown): value is Record<string, unknown> {
270
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
271
+ }
272
+
273
+ function parseAttesterExitAuthorization(value: unknown, index: number): AttesterExitAuthorization {
274
+ if (!isRecord(value)) {
275
+ throw new Error(`Attester exit authorization ${index} must be an object`);
276
+ }
277
+
278
+ const authorization = value;
279
+ if (typeof authorization.attester !== 'string') {
280
+ throw new Error(`Attester exit authorization ${index} has an invalid attester`);
281
+ }
282
+ if (typeof authorization.deadline !== 'string' || !/^\d+$/.test(authorization.deadline)) {
283
+ throw new Error(`Attester exit authorization ${index} deadline must be a decimal string`);
284
+ }
285
+ if (typeof authorization.signature !== 'string' || !isHex(authorization.signature)) {
286
+ throw new Error(`Attester exit authorization ${index} has an invalid signature`);
287
+ }
288
+
289
+ return {
290
+ attester: EthAddress.fromString(authorization.attester),
291
+ deadline: BigInt(authorization.deadline),
292
+ signature: Signature.fromString(authorization.signature).toViemSignature(),
293
+ };
294
+ }
295
+
296
+ /** Relays a batch of attester-signed exits. */
297
+ export async function initiateWithdrawByAttesterBatch({
298
+ rpcUrls,
299
+ chainId,
300
+ privateKey,
301
+ mnemonic,
302
+ authorizations,
303
+ upToLimit,
304
+ rollupAddress,
305
+ log,
306
+ debugLogger,
307
+ }: Omit<RollupCommandArgs, 'withdrawerAddress'> &
308
+ LoggerArgs & {
309
+ authorizations: AttesterExitAuthorization[];
310
+ upToLimit: boolean;
311
+ }) {
312
+ const account = getAccount(privateKey, mnemonic);
313
+ const chain = createEthereumChain(rpcUrls, chainId);
314
+ const client = createExtendedL1Client(rpcUrls, account, chain.chainInfo);
315
+ const rollup = new RollupContract(client, rollupAddress);
316
+ const l1TxUtils = createL1TxUtils(client, { logger: debugLogger });
317
+ const { receipt } = upToLimit
318
+ ? await rollup.initiateWithdrawByAttesterBatchUpToLimit(l1TxUtils, authorizations)
319
+ : await rollup.initiateWithdrawByAttesterBatch(l1TxUtils, authorizations);
320
+
321
+ if (receipt.status !== 'success') {
322
+ throw new Error(`Attester exit batch reverted: ${receipt.transactionHash}`);
323
+ }
324
+
325
+ log(`Submitted ${authorizations.length} attester exit authorizations. Transaction hash: ${receipt.transactionHash}`);
326
+ if (upToLimit) {
327
+ log('The rollup processed the largest permitted prefix of the authorization list.');
328
+ }
329
+ debugLogger.info('Attester exit batch submitted', {
330
+ authorizationCount: authorizations.length,
331
+ upToLimit,
332
+ rollup: rollupAddress.toString(),
333
+ transactionHash: receipt.transactionHash,
334
+ });
335
+ return receipt;
336
+ }
337
+
338
+ /** Initiates an attester exit without changing the registered withdrawer's control over the payout. */
339
+ export async function initiateWithdrawByAttester({
340
+ rpcUrls,
341
+ chainId,
342
+ privateKey,
343
+ mnemonic,
344
+ attesterAddress,
345
+ rollupAddress,
346
+ log,
347
+ debugLogger,
348
+ }: Omit<RollupCommandArgs, 'withdrawerAddress'> & LoggerArgs & { attesterAddress: EthAddress }) {
349
+ const account = getAccount(privateKey, mnemonic);
350
+ if (account.address.toLowerCase() !== attesterAddress.toString().toLowerCase()) {
351
+ throw new Error('The transaction signer must match the attester address');
352
+ }
353
+ const chain = createEthereumChain(rpcUrls, chainId);
354
+ const client = createExtendedL1Client(rpcUrls, account, chain.chainInfo);
355
+ const rollup = new RollupContract(client, rollupAddress);
356
+ const l1TxUtils = createL1TxUtils(client, { logger: debugLogger });
357
+ const { receipt } = await rollup.initiateWithdrawByAttester(l1TxUtils, attesterAddress);
358
+ if (receipt.status !== 'success') {
359
+ throw new Error(`Attester exit reverted: ${receipt.transactionHash}`);
360
+ }
361
+ log(`Attester exit initiated for ${attesterAddress}. Transaction hash: ${receipt.transactionHash}`);
362
+ log('The registered withdrawer must select a recipient using initiateWithdraw before finalization.');
363
+ debugLogger.info('Attester exit initiated', {
364
+ attester: attesterAddress.toString(),
365
+ rollup: rollupAddress.toString(),
366
+ transactionHash: receipt.transactionHash,
367
+ });
368
+ return receipt;
369
+ }
370
+
257
371
  export async function pruneRollup({
258
372
  rpcUrls,
259
373
  chainId,