@aztec-labs/cli 6.0.0-nightly.20261006 → 6.0.0-nightly.20261007
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.
- package/dest/cmds/l1/index.d.ts +1 -1
- package/dest/cmds/l1/index.d.ts.map +1 -1
- package/dest/cmds/l1/index.js +56 -3
- package/dest/cmds/l1/l1_rpc_test_utils.d.ts +14 -0
- package/dest/cmds/l1/l1_rpc_test_utils.d.ts.map +1 -0
- package/dest/cmds/l1/l1_rpc_test_utils.js +58 -0
- package/dest/cmds/l1/update_l1_validators.d.ts +47 -4
- package/dest/cmds/l1/update_l1_validators.d.ts.map +1 -1
- package/dest/cmds/l1/update_l1_validators.js +216 -22
- package/package.json +23 -23
- package/src/cmds/l1/index.ts +135 -10
- package/src/cmds/l1/l1_rpc_test_utils.ts +43 -0
- package/src/cmds/l1/update_l1_validators.ts +294 -27
package/dest/cmds/l1/index.d.ts
CHANGED
|
@@ -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,
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jbWRzL2wxL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsS0FBSyxPQUFPLEVBQVUsTUFBTSxXQUFXLENBQUM7QUF3QmpELHdCQUFnQixjQUFjLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLFdBbW1CL0UifQ==
|
|
@@ -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;
|
|
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;AAwBjD,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,WAmmB/E"}
|
package/dest/cmds/l1/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CheckpointNumber } from '@aztec-labs/foundation/branded-types';
|
|
2
2
|
import { EthAddress } from '@aztec-labs/foundation/eth-address';
|
|
3
3
|
import { Option } from 'commander';
|
|
4
|
-
import { ETHEREUM_HOSTS, MNEMONIC, PRIVATE_KEY, l1ChainIdOption, nodeOption, parseBigint, parseEthereumAddress } from '../../utils/commands.js';
|
|
4
|
+
import { ETHEREUM_HOSTS, MNEMONIC, PRIVATE_KEY, l1ChainIdOption, nodeOption, parseBigint, parseEthereumAddress, parseOptionalInteger } from '../../utils/commands.js';
|
|
5
5
|
const l1RpcUrlsOption = new Option('--l1-rpc-urls <string>', 'List of Ethereum host URLs. Chain identifiers localhost and testnet can be used (comma separated)').env('ETHEREUM_HOSTS').default([
|
|
6
6
|
ETHEREUM_HOSTS
|
|
7
7
|
]).makeOptionMandatory(true).argParser((arg)=>arg.split(',').map((url)=>url.trim()));
|
|
@@ -120,28 +120,67 @@ 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).
|
|
123
|
+
addSignerOptions(program.command('initiate-withdraw-by-attester').description("Initiates a withdrawal signed by the position's attester."), 'attester').addOption(l1RpcUrlsOption).addOption(l1ChainIdOption).requiredOption('--attester <address>', 'Attester address of the position to exit', parseEthereumAddress).requiredOption('--rollup <address>', 'Rollup holding the position', parseEthereumAddress).action(async (options)=>{
|
|
124
124
|
const { initiateWithdrawByAttester } = await import('./update_l1_validators.js');
|
|
125
125
|
await initiateWithdrawByAttester({
|
|
126
126
|
rpcUrls: options.l1RpcUrls,
|
|
127
127
|
chainId: options.l1ChainId,
|
|
128
128
|
privateKey: options.privateKey,
|
|
129
129
|
mnemonic: options.mnemonic,
|
|
130
|
+
accountIndex: options.accountIndex,
|
|
131
|
+
addressIndex: options.addressIndex,
|
|
130
132
|
attesterAddress: options.attester,
|
|
131
133
|
rollupAddress: options.rollup,
|
|
132
134
|
log,
|
|
133
135
|
debugLogger
|
|
134
136
|
});
|
|
135
137
|
});
|
|
136
|
-
program.command('
|
|
138
|
+
addSignerOptions(program.command('sign-attester-exit').description('Signs an exit authorization locally and writes a JSON array for batch submission.'), 'attester').addOption(new Option('--l1-rpc-urls <string>', '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').env('ETHEREUM_HOSTS').argParser((arg)=>arg.split(',').map((url)=>url.trim()))).addOption(new Option('-c, --l1-chain-id <number>', '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').env('L1_CHAIN_ID').argParser(Number)).addOption(networkOption).requiredOption('--attester <address>', 'Attester address of the position to exit', parseEthereumAddress).option('--rollup <address>', 'Rollup holding the position; defaults to the canonical rollup of --network', parseEthereumAddress).requiredOption('--deadline <timestamp>', 'Authorization expiry as Unix seconds', parseBigint).requiredOption('--output <path>', 'JSON output file (must be new unless --append is used)').option('--append', 'Append or create if missing, without validating existing authorizations; run initiate-withdraw-by-attester-batch --dry-run after the batch is complete').addHelpText('after', `
|
|
139
|
+
Examples:
|
|
140
|
+
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
|
|
141
|
+
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
|
|
142
|
+
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
|
|
143
|
+
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
|
|
144
|
+
aztec initiate-withdraw-by-attester-batch --dry-run --authorizations exits.json --rollup "$ROLLUP" --l1-chain-id "$CHAIN_ID" --l1-rpc-urls "$L1_RPC_URL"
|
|
145
|
+
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"
|
|
146
|
+
Note: DEADLINE is a future Unix timestamp in seconds. Run append commands sequentially.
|
|
147
|
+
`).action(async (options, command)=>{
|
|
148
|
+
const { getAttesterExitNetwork, resolveAttesterExitTarget, signAttesterExit } = await import('./update_l1_validators.js');
|
|
149
|
+
const { chainId, rollupAddress } = await resolveAttesterExitTarget({
|
|
150
|
+
chainId: options.l1ChainId,
|
|
151
|
+
chainIdFromEnv: command.getOptionValueSource('l1ChainId') === 'env',
|
|
152
|
+
rpcUrls: options.l1RpcUrls,
|
|
153
|
+
network: options.network ? await getAttesterExitNetwork(options.network) : undefined,
|
|
154
|
+
rollupAddress: options.rollup,
|
|
155
|
+
log
|
|
156
|
+
});
|
|
157
|
+
await signAttesterExit({
|
|
158
|
+
rpcUrls: options.l1RpcUrls ?? [],
|
|
159
|
+
chainId,
|
|
160
|
+
privateKey: options.privateKey,
|
|
161
|
+
mnemonic: options.mnemonic,
|
|
162
|
+
accountIndex: options.accountIndex,
|
|
163
|
+
addressIndex: options.addressIndex,
|
|
164
|
+
attesterAddress: options.attester,
|
|
165
|
+
rollupAddress,
|
|
166
|
+
deadline: options.deadline,
|
|
167
|
+
output: options.output,
|
|
168
|
+
append: options.append,
|
|
169
|
+
log
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
addSignerOptions(program.command('initiate-withdraw-by-attester-batch').description('Relays a JSON array of attester-signed withdrawal authorizations.'), 'relayer').addOption(l1RpcUrlsOption).addOption(l1ChainIdOption).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').option('--dry-run', 'Simulate against current chain state without sending; no relayer key is required').action(async (options)=>{
|
|
137
173
|
const { initiateWithdrawByAttesterBatch, readAttesterExitAuthorizations } = await import('./update_l1_validators.js');
|
|
138
174
|
await initiateWithdrawByAttesterBatch({
|
|
139
175
|
rpcUrls: options.l1RpcUrls,
|
|
140
176
|
chainId: options.l1ChainId,
|
|
141
177
|
privateKey: options.privateKey,
|
|
142
178
|
mnemonic: options.mnemonic,
|
|
179
|
+
accountIndex: options.accountIndex,
|
|
180
|
+
addressIndex: options.addressIndex,
|
|
143
181
|
authorizations: await readAttesterExitAuthorizations(options.authorizations),
|
|
144
182
|
upToLimit: options.upToLimit,
|
|
183
|
+
dryRun: options.dryRun,
|
|
145
184
|
rollupAddress: options.rollup,
|
|
146
185
|
log,
|
|
147
186
|
debugLogger
|
|
@@ -226,3 +265,17 @@ export function injectCommands(program, log, debugLogger) {
|
|
|
226
265
|
});
|
|
227
266
|
return program;
|
|
228
267
|
}
|
|
268
|
+
function addSignerOptions(command, role) {
|
|
269
|
+
return command.addOption(new Option('-pk, --private-key <string>', `The ${role} private key; supply this or --mnemonic`).env('PRIVATE_KEY')).addOption(new Option('-m, --mnemonic <string>', `Mnemonic for the ${role} account; a flag overrides the other credential from the environment, and PRIVATE_KEY wins when both come from the environment`).env('MNEMONIC')).option('--account-index <number>', 'Mnemonic account index, matching validator-keys generation (default: 0; requires --mnemonic)', (value)=>parseOptionalInteger(value, 0)).option('--address-index <number>', role === 'attester' ? 'Mnemonic address index: validator-keys base address index + zero-based validator position; third validator = base + 2 (default: 0; requires --mnemonic)' : 'Mnemonic address index for the relayer paying for the transaction; attesters sign authorizations separately (default: 0; requires --mnemonic)', (value)=>parseOptionalInteger(value, 0)).hook('preAction', (_, actionCommand)=>{
|
|
270
|
+
const { privateKey, mnemonic } = actionCommand.opts();
|
|
271
|
+
if (!privateKey || !mnemonic) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
// Only two credentials passed as flags are a conflict; otherwise drop the one that came from the environment.
|
|
275
|
+
if (actionCommand.getOptionValueSource('mnemonic') === 'env') {
|
|
276
|
+
actionCommand.setOptionValue('mnemonic', undefined);
|
|
277
|
+
} else if (actionCommand.getOptionValueSource('privateKey') === 'env') {
|
|
278
|
+
actionCommand.setOptionValue('privateKey', undefined);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EthAddress } from '@aztec-labs/foundation/eth-address';
|
|
2
|
+
/**
|
|
3
|
+
* Starts a JSON-RPC server that reports `chainId` and, when `canonicalRollup` is given, answers every `eth_call` with
|
|
4
|
+
* that address and records the call. Any other method gets an error.
|
|
5
|
+
*/
|
|
6
|
+
export declare function serveL1Rpc(chainId: number, canonicalRollup?: EthAddress): Promise<{
|
|
7
|
+
url: string;
|
|
8
|
+
registryCalls: {
|
|
9
|
+
to: string;
|
|
10
|
+
data: string;
|
|
11
|
+
}[];
|
|
12
|
+
close: () => Promise<unknown>;
|
|
13
|
+
}>;
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibDFfcnBjX3Rlc3RfdXRpbHMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jbWRzL2wxL2wxX3JwY190ZXN0X3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBSXJFOzs7R0FHRztBQUNILHdCQUFzQixVQUFVLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxlQUFlLENBQUMsRUFBRSxVQUFVOzs7Ozs7O0dBa0M3RSJ9
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"l1_rpc_test_utils.d.ts","sourceRoot":"","sources":["../../../src/cmds/l1/l1_rpc_test_utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAIrE;;;GAGG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,UAAU;;;;;;;GAkC7E"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
import { encodeAbiParameters } from 'viem';
|
|
3
|
+
/**
|
|
4
|
+
* Starts a JSON-RPC server that reports `chainId` and, when `canonicalRollup` is given, answers every `eth_call` with
|
|
5
|
+
* that address and records the call. Any other method gets an error.
|
|
6
|
+
*/ export async function serveL1Rpc(chainId, canonicalRollup) {
|
|
7
|
+
const registryCalls = [];
|
|
8
|
+
const server = createServer((request, response)=>{
|
|
9
|
+
let body = '';
|
|
10
|
+
request.on('data', (chunk)=>body += chunk);
|
|
11
|
+
request.on('end', ()=>{
|
|
12
|
+
const { id, method, params } = JSON.parse(body);
|
|
13
|
+
response.setHeader('content-type', 'application/json');
|
|
14
|
+
if (method === 'eth_chainId') {
|
|
15
|
+
response.end(JSON.stringify({
|
|
16
|
+
jsonrpc: '2.0',
|
|
17
|
+
id,
|
|
18
|
+
result: `0x${chainId.toString(16)}`
|
|
19
|
+
}));
|
|
20
|
+
} else if (method === 'eth_call' && canonicalRollup) {
|
|
21
|
+
registryCalls.push({
|
|
22
|
+
to: params[0].to,
|
|
23
|
+
data: params[0].data
|
|
24
|
+
});
|
|
25
|
+
response.end(JSON.stringify({
|
|
26
|
+
jsonrpc: '2.0',
|
|
27
|
+
id,
|
|
28
|
+
result: encodeAbiParameters([
|
|
29
|
+
{
|
|
30
|
+
type: 'address'
|
|
31
|
+
}
|
|
32
|
+
], [
|
|
33
|
+
canonicalRollup.toString()
|
|
34
|
+
])
|
|
35
|
+
}));
|
|
36
|
+
} else {
|
|
37
|
+
response.end(JSON.stringify({
|
|
38
|
+
jsonrpc: '2.0',
|
|
39
|
+
id,
|
|
40
|
+
error: {
|
|
41
|
+
code: -32601,
|
|
42
|
+
message: 'Unsupported method'
|
|
43
|
+
}
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
await new Promise((resolve)=>server.listen(0, '127.0.0.1', resolve));
|
|
49
|
+
const address = server.address();
|
|
50
|
+
if (!address || typeof address === 'string') {
|
|
51
|
+
throw new Error('Expected a TCP server address');
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
url: `http://127.0.0.1:${address.port}`,
|
|
55
|
+
registryCalls,
|
|
56
|
+
close: ()=>new Promise((resolve)=>server.close(resolve))
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -9,6 +9,13 @@ export interface RollupCommandArgs {
|
|
|
9
9
|
rollupAddress: EthAddress;
|
|
10
10
|
withdrawerAddress?: EthAddress;
|
|
11
11
|
}
|
|
12
|
+
/** Credentials and derivation indices for a local Ethereum signer. */
|
|
13
|
+
export type SignerAccountArgs = {
|
|
14
|
+
privateKey?: string;
|
|
15
|
+
mnemonic?: string;
|
|
16
|
+
accountIndex?: number;
|
|
17
|
+
addressIndex?: number;
|
|
18
|
+
};
|
|
12
19
|
export interface StakingAssetHandlerCommandArgs {
|
|
13
20
|
rpcUrls: string[];
|
|
14
21
|
chainId: number;
|
|
@@ -38,15 +45,51 @@ export declare function addL1ValidatorViaRollup({ rpcUrls, chainId, privateKey,
|
|
|
38
45
|
export declare function removeL1Validator({ rpcUrls, chainId, privateKey, mnemonic, validatorAddress, rollupAddress, log, debugLogger }: RollupCommandArgs & LoggerArgs & {
|
|
39
46
|
validatorAddress: EthAddress;
|
|
40
47
|
}): Promise<void>;
|
|
48
|
+
/** Chain ID and registry published for a network; both are undefined when it publishes none, as for `local`. */
|
|
49
|
+
export type AttesterExitNetwork = {
|
|
50
|
+
name: string;
|
|
51
|
+
l1ChainId?: number;
|
|
52
|
+
registryAddress?: EthAddress;
|
|
53
|
+
};
|
|
54
|
+
/** Loads the published config of the network selected with --network, which takes precedence over the environment. */
|
|
55
|
+
export declare function getAttesterExitNetwork(name: string): Promise<AttesterExitNetwork>;
|
|
56
|
+
/** Inputs that select the chain and rollup an attester exit is signed for; each is undefined when not supplied. */
|
|
57
|
+
export type AttesterExitTargetArgs = {
|
|
58
|
+
chainId?: number;
|
|
59
|
+
/** Whether `chainId` came from the L1_CHAIN_ID environment variable rather than a flag. */
|
|
60
|
+
chainIdFromEnv?: boolean;
|
|
61
|
+
rpcUrls?: string[];
|
|
62
|
+
network?: AttesterExitNetwork;
|
|
63
|
+
rollupAddress?: EthAddress;
|
|
64
|
+
log: LogFn;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Resolves the chain ID and rollup an attester exit is signed for, without falling back to the Anvil chain ID.
|
|
68
|
+
* Whenever an RPC is given, its chain ID must match. Without one, signing is offline and needs the chain ID from a flag
|
|
69
|
+
* or --network; an L1_CHAIN_ID left in the environment alone is rejected because nothing confirms it.
|
|
70
|
+
*/
|
|
71
|
+
export declare function resolveAttesterExitTarget({ chainId, chainIdFromEnv, rpcUrls, network, rollupAddress, log }: AttesterExitTargetArgs): Promise<{
|
|
72
|
+
chainId: number;
|
|
73
|
+
rollupAddress: EthAddress;
|
|
74
|
+
}>;
|
|
75
|
+
/** Signs an exit authorization locally and writes a JSON array accepted by the batch command. */
|
|
76
|
+
export declare function signAttesterExit({ rpcUrls, chainId, privateKey, mnemonic, accountIndex, addressIndex, rollupAddress, attesterAddress, deadline, output, append, log }: Omit<RollupCommandArgs, 'withdrawerAddress' | 'mnemonic' | 'privateKey'> & SignerAccountArgs & {
|
|
77
|
+
attesterAddress: EthAddress;
|
|
78
|
+
deadline: bigint;
|
|
79
|
+
output: string;
|
|
80
|
+
append?: boolean;
|
|
81
|
+
log: LogFn;
|
|
82
|
+
}): Promise<void>;
|
|
41
83
|
/** Reads relayed attester exit authorizations from a JSON array. */
|
|
42
84
|
export declare function readAttesterExitAuthorizations(path: string): Promise<AttesterExitAuthorization[]>;
|
|
43
85
|
/** 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 & {
|
|
86
|
+
export declare function initiateWithdrawByAttesterBatch({ rpcUrls, chainId, privateKey, mnemonic, accountIndex, addressIndex, authorizations, upToLimit, dryRun, rollupAddress, log, debugLogger }: Omit<RollupCommandArgs, 'withdrawerAddress' | 'mnemonic' | 'privateKey'> & SignerAccountArgs & LoggerArgs & {
|
|
45
87
|
authorizations: AttesterExitAuthorization[];
|
|
46
88
|
upToLimit: boolean;
|
|
47
|
-
|
|
89
|
+
dryRun?: boolean;
|
|
90
|
+
}): Promise<import("viem").TransactionReceipt | undefined>;
|
|
48
91
|
/** 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 & {
|
|
92
|
+
export declare function initiateWithdrawByAttester({ rpcUrls, chainId, privateKey, mnemonic, accountIndex, addressIndex, attesterAddress, rollupAddress, log, debugLogger }: Omit<RollupCommandArgs, 'withdrawerAddress' | 'mnemonic' | 'privateKey'> & SignerAccountArgs & LoggerArgs & {
|
|
50
93
|
attesterAddress: EthAddress;
|
|
51
94
|
}): Promise<import("viem").TransactionReceipt>;
|
|
52
95
|
export declare function pruneRollup({ rpcUrls, chainId, privateKey, mnemonic, rollupAddress, log, debugLogger }: RollupCommandArgs & LoggerArgs): Promise<void>;
|
|
@@ -54,4 +97,4 @@ export declare function fastForwardEpochs({ rpcUrls, chainId, rollupAddress, num
|
|
|
54
97
|
numEpochs: bigint;
|
|
55
98
|
}): Promise<void>;
|
|
56
99
|
export declare function debugRollup({ rpcUrls, chainId, rollupAddress, log }: RollupCommandArgs & LoggerArgs): Promise<void>;
|
|
57
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
100
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlX2wxX3ZhbGlkYXRvcnMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jbWRzL2wxL3VwZGF0ZV9sMV92YWxpZGF0b3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUtBLE9BQU8sRUFDTCxLQUFLLHlCQUF5QixFQUkvQixNQUFNLGdDQUFnQyxDQUFDO0FBSXhDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUVoRSxPQUFPLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFZaEUsTUFBTSxXQUFXLGlCQUFpQjtJQUNoQyxPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUM7SUFDbEIsT0FBTyxFQUFFLE1BQU0sQ0FBQztJQUNoQixVQUFVLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDcEIsUUFBUSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2xCLGFBQWEsRUFBRSxVQUFVLENBQUM7SUFDMUIsaUJBQWlCLENBQUMsRUFBRSxVQUFVLENBQUM7Q0FDaEM7QUFFRCxzRUFBc0U7QUFDdEUsTUFBTSxNQUFNLGlCQUFpQixHQUFHO0lBQzlCLFVBQVUsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNwQixRQUFRLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDbEIsWUFBWSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLFlBQVksQ0FBQyxFQUFFLE1BQU0sQ0FBQztDQUN2QixDQUFDO0FBRUYsTUFBTSxXQUFXLDhCQUE4QjtJQUM3QyxPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUM7SUFDbEIsT0FBTyxFQUFFLE1BQU0sQ0FBQztJQUNoQixVQUFVLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDcEIsUUFBUSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2xCLDBCQUEwQixFQUFFLFVBQVUsQ0FBQztDQUN4QztBQUVELE1BQU0sV0FBVyxVQUFVO0lBQ3pCLEdBQUcsRUFBRSxLQUFLLENBQUM7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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":"AAKA,OAAO,
|
|
1
|
+
{"version":3,"file":"update_l1_validators.d.ts","sourceRoot":"","sources":["../../../src/cmds/l1/update_l1_validators.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { RollupAbi, StakingAssetHandlerAbi, TestERC20Abi } from '@aztec-foundation/l1-artifacts';
|
|
2
2
|
import { createEthereumChain, isAnvilTestChain } from '@aztec-labs/ethereum/chain';
|
|
3
|
-
import { createExtendedL1Client, getPublicClient } from '@aztec-labs/ethereum/client';
|
|
3
|
+
import { createExtendedL1Client, getPublicClient, makeL1HttpTransport } from '@aztec-labs/ethereum/client';
|
|
4
4
|
import { getL1ContractsConfigEnvVars } from '@aztec-labs/ethereum/config';
|
|
5
|
-
import { GSEContract, RollupContract } from '@aztec-labs/ethereum/contracts';
|
|
5
|
+
import { GSEContract, RegistryContract, 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 { getActiveNetworkName } from '@aztec-labs/foundation/config';
|
|
8
9
|
import { EthAddress } from '@aztec-labs/foundation/eth-address';
|
|
9
10
|
import { Signature } from '@aztec-labs/foundation/eth-signature';
|
|
10
11
|
import { DateProvider } from '@aztec-labs/foundation/timer';
|
|
11
12
|
import { ZkPassportProofParams } from '@aztec-labs/stdlib/zkpassport';
|
|
12
|
-
import { readFile } from 'node:fs/promises';
|
|
13
|
-
import {
|
|
13
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { createPublicClient, encodeFunctionData, formatEther, getContract, isHex, maxUint256 } from 'viem';
|
|
14
16
|
import { generatePrivateKey, mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
|
|
17
|
+
import { getNetworkConfig } from '../../config/network_config.js';
|
|
18
|
+
import { atomicUpdateFile } from '../../utils/commands.js';
|
|
19
|
+
import { deriveEthAttester } from '../validator_keys/shared.js';
|
|
15
20
|
export function generateL1Account() {
|
|
16
21
|
const privateKey = generatePrivateKey();
|
|
17
22
|
const account = privateKeyToAccount(privateKey);
|
|
@@ -191,13 +196,131 @@ export async function removeL1Validator({ rpcUrls, chainId, privateKey, mnemonic
|
|
|
191
196
|
});
|
|
192
197
|
dualLog(`Transaction hash: ${receipt.transactionHash}`);
|
|
193
198
|
}
|
|
199
|
+
/** Loads the published config of the network selected with --network, which takes precedence over the environment. */ export async function getAttesterExitNetwork(name) {
|
|
200
|
+
const networkName = getActiveNetworkName(name);
|
|
201
|
+
const cacheDir = process.env.DATA_DIRECTORY ? join(process.env.DATA_DIRECTORY, 'cache') : undefined;
|
|
202
|
+
const config = networkName === 'local' ? undefined : await getNetworkConfig(networkName, cacheDir);
|
|
203
|
+
if (networkName !== 'local' && !config) {
|
|
204
|
+
throw new Error(`Network ${networkName} has no published config`);
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
name: networkName,
|
|
208
|
+
l1ChainId: config?.l1ChainId,
|
|
209
|
+
registryAddress: config ? EthAddress.fromString(config.registryAddress) : undefined
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Resolves the chain ID and rollup an attester exit is signed for, without falling back to the Anvil chain ID.
|
|
214
|
+
* Whenever an RPC is given, its chain ID must match. Without one, signing is offline and needs the chain ID from a flag
|
|
215
|
+
* or --network; an L1_CHAIN_ID left in the environment alone is rejected because nothing confirms it.
|
|
216
|
+
*/ export async function resolveAttesterExitTarget({ chainId, chainIdFromEnv = false, rpcUrls, network, rollupAddress, log }) {
|
|
217
|
+
if (!rollupAddress && !network) {
|
|
218
|
+
throw new Error('Provide --rollup, or --network to use the canonical rollup from the network registry');
|
|
219
|
+
}
|
|
220
|
+
if (!rollupAddress && !network?.registryAddress) {
|
|
221
|
+
throw new Error(`Network ${network?.name} publishes no registry address; provide --rollup`);
|
|
222
|
+
}
|
|
223
|
+
if (chainId !== undefined) {
|
|
224
|
+
assertValidChainId(chainId);
|
|
225
|
+
if (network?.l1ChainId !== undefined && chainId !== network.l1ChainId) {
|
|
226
|
+
throw new Error(`Chain ID ${chainId} does not match ${network.name}, which uses chain ID ${network.l1ChainId}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const expectedChainId = chainId ?? network?.l1ChainId;
|
|
230
|
+
if (!rpcUrls) {
|
|
231
|
+
if (expectedChainId === undefined) {
|
|
232
|
+
throw new Error('Provide --l1-chain-id, --network, or --l1-rpc-urls to select the chain to sign for');
|
|
233
|
+
}
|
|
234
|
+
if (!rollupAddress) {
|
|
235
|
+
throw new Error('Looking up the rollup in the network registry requires --l1-rpc-urls');
|
|
236
|
+
}
|
|
237
|
+
if (chainIdFromEnv && network?.l1ChainId === undefined) {
|
|
238
|
+
throw new Error(`Chain ID ${expectedChainId} comes only from L1_CHAIN_ID; confirm it with --l1-chain-id, --network, or --l1-rpc-urls`);
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
chainId: expectedChainId,
|
|
242
|
+
rollupAddress
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
const rpcChainId = await getL1RpcChainId(rpcUrls, expectedChainId);
|
|
246
|
+
if (rollupAddress) {
|
|
247
|
+
return {
|
|
248
|
+
chainId: rpcChainId,
|
|
249
|
+
rollupAddress
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
const registryAddress = network.registryAddress;
|
|
253
|
+
const client = getPublicClient({
|
|
254
|
+
l1RpcUrls: rpcUrls,
|
|
255
|
+
l1ChainId: rpcChainId
|
|
256
|
+
});
|
|
257
|
+
const canonicalRollup = await new RegistryContract(client, registryAddress).getCanonicalAddress();
|
|
258
|
+
log(`Using canonical rollup ${canonicalRollup} from the ${network.name} registry ${registryAddress}`);
|
|
259
|
+
return {
|
|
260
|
+
chainId: rpcChainId,
|
|
261
|
+
rollupAddress: canonicalRollup
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/** Returns the chain ID the L1 RPC reports, failing if it differs from `expectedChainId`. */ async function getL1RpcChainId(rpcUrls, expectedChainId) {
|
|
265
|
+
const rpcChainId = await createPublicClient({
|
|
266
|
+
transport: makeL1HttpTransport(rpcUrls)
|
|
267
|
+
}).getChainId();
|
|
268
|
+
if (expectedChainId !== undefined && rpcChainId !== expectedChainId) {
|
|
269
|
+
throw new Error(`The L1 RPC reports chain ID ${rpcChainId}, but chain ID ${expectedChainId} was requested`);
|
|
270
|
+
}
|
|
271
|
+
return rpcChainId;
|
|
272
|
+
}
|
|
273
|
+
/** Signs an exit authorization locally and writes a JSON array accepted by the batch command. */ export async function signAttesterExit({ rpcUrls, chainId, privateKey, mnemonic, accountIndex, addressIndex, rollupAddress, attesterAddress, deadline, output, append = false, log }) {
|
|
274
|
+
assertValidChainId(chainId);
|
|
275
|
+
const account = getSignerAccount({
|
|
276
|
+
privateKey,
|
|
277
|
+
mnemonic,
|
|
278
|
+
accountIndex,
|
|
279
|
+
addressIndex
|
|
280
|
+
});
|
|
281
|
+
if (account.address.toLowerCase() !== attesterAddress.toString().toLowerCase()) {
|
|
282
|
+
throw new Error('The signing account must match the attester address');
|
|
283
|
+
}
|
|
284
|
+
const chain = createEthereumChain(rpcUrls, chainId);
|
|
285
|
+
const client = createExtendedL1Client(rpcUrls, account, chain.chainInfo);
|
|
286
|
+
const rollup = new RollupContract(client, rollupAddress);
|
|
287
|
+
const authorization = await rollup.createAttesterExitAuthorization(attesterAddress, deadline, (typedData)=>account.signTypedData(typedData));
|
|
288
|
+
const existingAuthorizations = append ? await readAttesterExitAuthorizationJson(output).catch((error)=>{
|
|
289
|
+
if (!isRecord(error) || error.code !== 'ENOENT') {
|
|
290
|
+
throw error;
|
|
291
|
+
}
|
|
292
|
+
return undefined;
|
|
293
|
+
}) : undefined;
|
|
294
|
+
const authorizations = existingAuthorizations ?? [];
|
|
295
|
+
authorizations.push({
|
|
296
|
+
attester: authorization.attester.toString(),
|
|
297
|
+
deadline: authorization.deadline.toString(),
|
|
298
|
+
signature: Signature.fromViemSignature(authorization.signature).toString()
|
|
299
|
+
});
|
|
300
|
+
const json = JSON.stringify(authorizations, null, 2);
|
|
301
|
+
if (existingAuthorizations) {
|
|
302
|
+
await atomicUpdateFile(output, `${json}\n`);
|
|
303
|
+
} else {
|
|
304
|
+
await writeFile(output, `${json}\n`, {
|
|
305
|
+
flag: 'wx'
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
log(`Wrote attester exit authorization to ${output}`);
|
|
309
|
+
}
|
|
194
310
|
/** Reads relayed attester exit authorizations from a JSON array. */ export async function readAttesterExitAuthorizations(path) {
|
|
195
|
-
const parsed =
|
|
196
|
-
if (
|
|
311
|
+
const parsed = await readAttesterExitAuthorizationJson(path);
|
|
312
|
+
if (parsed.length === 0) {
|
|
197
313
|
throw new Error('Attester exit authorization file must contain a non-empty JSON array');
|
|
198
314
|
}
|
|
199
315
|
return parsed.map((value, index)=>parseAttesterExitAuthorization(value, index));
|
|
200
316
|
}
|
|
317
|
+
async function readAttesterExitAuthorizationJson(path) {
|
|
318
|
+
const parsed = JSON.parse(await readFile(path, 'utf-8'));
|
|
319
|
+
if (!Array.isArray(parsed)) {
|
|
320
|
+
throw new Error('Attester exit authorization file must contain a JSON array');
|
|
321
|
+
}
|
|
322
|
+
return parsed;
|
|
323
|
+
}
|
|
201
324
|
function isRecord(value) {
|
|
202
325
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
203
326
|
}
|
|
@@ -212,7 +335,7 @@ function parseAttesterExitAuthorization(value, index) {
|
|
|
212
335
|
if (typeof authorization.deadline !== 'string' || !/^\d+$/.test(authorization.deadline)) {
|
|
213
336
|
throw new Error(`Attester exit authorization ${index} deadline must be a decimal string`);
|
|
214
337
|
}
|
|
215
|
-
if (typeof authorization.signature !== 'string' || !isHex(authorization.signature)) {
|
|
338
|
+
if (typeof authorization.signature !== 'string' || !isHex(authorization.signature) || !Signature.isValidString(authorization.signature)) {
|
|
216
339
|
throw new Error(`Attester exit authorization ${index} has an invalid signature`);
|
|
217
340
|
}
|
|
218
341
|
return {
|
|
@@ -221,32 +344,73 @@ function parseAttesterExitAuthorization(value, index) {
|
|
|
221
344
|
signature: Signature.fromString(authorization.signature).toViemSignature()
|
|
222
345
|
};
|
|
223
346
|
}
|
|
224
|
-
/**
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
347
|
+
/**
|
|
348
|
+
* Confirms the RPC is on the requested chain, then checks each imported signature so a bad entry is named rather than
|
|
349
|
+
* reverting the whole batch. Duplicates and deadlines are left to the chain, which with --up-to-limit never looks past
|
|
350
|
+
* the processed prefix.
|
|
351
|
+
*/ async function checkAttesterExitBatch(rollup, authorizations, rpcUrls, chainId) {
|
|
352
|
+
await getL1RpcChainId(rpcUrls, chainId);
|
|
353
|
+
for (const [index, authorization] of authorizations.entries()){
|
|
354
|
+
await rollup.validateAttesterExitSignature(authorization, index);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
/** Relays a batch of attester-signed exits. */ export async function initiateWithdrawByAttesterBatch({ rpcUrls, chainId, privateKey, mnemonic, accountIndex, addressIndex, authorizations, upToLimit, dryRun = false, rollupAddress, log, debugLogger }) {
|
|
358
|
+
if (dryRun) {
|
|
359
|
+
assertValidChainId(chainId);
|
|
360
|
+
// A dry run needs no key, but check any signer options given so the same command can later run without --dry-run.
|
|
361
|
+
if (privateKey || mnemonic || accountIndex !== undefined || addressIndex !== undefined) {
|
|
362
|
+
getSignerAccount({
|
|
363
|
+
privateKey,
|
|
364
|
+
mnemonic,
|
|
365
|
+
accountIndex,
|
|
366
|
+
addressIndex
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
const client = getPublicClient({
|
|
370
|
+
l1RpcUrls: rpcUrls,
|
|
371
|
+
l1ChainId: chainId
|
|
372
|
+
});
|
|
373
|
+
const rollup = new RollupContract(client, rollupAddress);
|
|
374
|
+
await checkAttesterExitBatch(rollup, authorizations, rpcUrls, chainId);
|
|
375
|
+
const processedCount = await rollup.simulateAttesterExitBatch(authorizations, upToLimit);
|
|
376
|
+
log(`Dry run: would process ${processedCount} of ${authorizations.length} attester exit authorizations at current chain state.`);
|
|
377
|
+
logRemainingAttesterExits(log, processedCount, authorizations.length);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const account = getSignerAccount({
|
|
381
|
+
privateKey,
|
|
382
|
+
mnemonic,
|
|
383
|
+
accountIndex,
|
|
384
|
+
addressIndex
|
|
385
|
+
});
|
|
386
|
+
const client = createExtendedL1Client(rpcUrls, account, createEthereumChain(rpcUrls, chainId).chainInfo);
|
|
228
387
|
const rollup = new RollupContract(client, rollupAddress);
|
|
388
|
+
await checkAttesterExitBatch(rollup, authorizations, rpcUrls, chainId);
|
|
229
389
|
const l1TxUtils = createL1TxUtils(client, {
|
|
230
390
|
logger: debugLogger
|
|
231
391
|
});
|
|
232
|
-
const { receipt } =
|
|
233
|
-
|
|
234
|
-
|
|
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', {
|
|
392
|
+
const { receipt, processedCount, remainingCount } = await rollup.submitAttesterExitBatch(l1TxUtils, authorizations, upToLimit);
|
|
393
|
+
log(`Processed ${processedCount} of ${authorizations.length} attester exit authorizations. Transaction hash: ${receipt.transactionHash}`);
|
|
394
|
+
logRemainingAttesterExits(log, processedCount, authorizations.length);
|
|
395
|
+
debugLogger.info('Attester exit batch processed', {
|
|
241
396
|
authorizationCount: authorizations.length,
|
|
397
|
+
processedCount,
|
|
398
|
+
remainingCount,
|
|
399
|
+
remainingStartIndex: remainingCount > 0 ? processedCount : undefined,
|
|
400
|
+
remainingEndIndexExclusive: remainingCount > 0 ? authorizations.length : undefined,
|
|
242
401
|
upToLimit,
|
|
243
402
|
rollup: rollupAddress.toString(),
|
|
244
403
|
transactionHash: receipt.transactionHash
|
|
245
404
|
});
|
|
246
405
|
return receipt;
|
|
247
406
|
}
|
|
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 =
|
|
407
|
+
/** Initiates an attester exit without changing the registered withdrawer's control over the payout. */ export async function initiateWithdrawByAttester({ rpcUrls, chainId, privateKey, mnemonic, accountIndex, addressIndex, attesterAddress, rollupAddress, log, debugLogger }) {
|
|
408
|
+
const account = getSignerAccount({
|
|
409
|
+
privateKey,
|
|
410
|
+
mnemonic,
|
|
411
|
+
accountIndex,
|
|
412
|
+
addressIndex
|
|
413
|
+
});
|
|
250
414
|
if (account.address.toLowerCase() !== attesterAddress.toString().toLowerCase()) {
|
|
251
415
|
throw new Error('The transaction signer must match the attester address');
|
|
252
416
|
}
|
|
@@ -346,12 +510,42 @@ export async function debugRollup({ rpcUrls, chainId, rollupAddress, log }) {
|
|
|
346
510
|
const proposer = await rollup.getProposerAt(nextBlockTS);
|
|
347
511
|
log(`Proposer NOW: ${proposer.toString()}`);
|
|
348
512
|
}
|
|
513
|
+
function logRemainingAttesterExits(log, processedCount, authorizationCount) {
|
|
514
|
+
const remainingCount = authorizationCount - processedCount;
|
|
515
|
+
log(remainingCount > 0 ? `Remaining authorizations: ${remainingCount}. Zero-based JSON array indices ${processedCount} through ${authorizationCount - 1} (inclusive).` : 'Remaining authorizations: 0 (none).');
|
|
516
|
+
}
|
|
349
517
|
function makeDualLog(log, debugLogger) {
|
|
350
518
|
return (msg)=>{
|
|
351
519
|
log(msg);
|
|
352
520
|
debugLogger.info(msg);
|
|
353
521
|
};
|
|
354
522
|
}
|
|
523
|
+
/** `createEthereumChain` maps a falsy chain ID to Anvil, so reject it before a chain is built from it. */ function assertValidChainId(chainId) {
|
|
524
|
+
if (!Number.isSafeInteger(chainId) || chainId <= 0) {
|
|
525
|
+
throw new Error('Chain ID must be a positive safe integer');
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function getSignerAccount({ privateKey, mnemonic, accountIndex, addressIndex }) {
|
|
529
|
+
if (Boolean(privateKey) === Boolean(mnemonic)) {
|
|
530
|
+
throw new Error('Provide either a private key or a mnemonic for the signer');
|
|
531
|
+
}
|
|
532
|
+
if (privateKey) {
|
|
533
|
+
if (accountIndex !== undefined || addressIndex !== undefined) {
|
|
534
|
+
throw new Error('Account and address indices require a mnemonic');
|
|
535
|
+
}
|
|
536
|
+
return getAccount(privateKey, undefined);
|
|
537
|
+
}
|
|
538
|
+
const selectedAccountIndex = accountIndex ?? 0;
|
|
539
|
+
const selectedAddressIndex = addressIndex ?? 0;
|
|
540
|
+
if (!Number.isSafeInteger(selectedAccountIndex) || selectedAccountIndex < 0 || !Number.isSafeInteger(selectedAddressIndex) || selectedAddressIndex < 0) {
|
|
541
|
+
throw new Error('Account and address indices must be non-negative safe integers');
|
|
542
|
+
}
|
|
543
|
+
const derivedKey = deriveEthAttester(mnemonic, selectedAccountIndex, selectedAddressIndex);
|
|
544
|
+
if (typeof derivedKey !== 'string') {
|
|
545
|
+
throw new Error('Expected a local signer private key');
|
|
546
|
+
}
|
|
547
|
+
return privateKeyToAccount(derivedKey);
|
|
548
|
+
}
|
|
355
549
|
function getAccount(privateKey, mnemonic) {
|
|
356
550
|
if (!privateKey && !mnemonic) {
|
|
357
551
|
throw new Error('Either privateKey or mnemonic must be provided to create a wallet client');
|