@aztec/cli 3.0.0-nightly.20250908 → 3.0.0-nightly.20250910

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 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmds/l1/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAG3D,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,WAAW,CAAC;AAajD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAW3D,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,WAkhB/E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmds/l1/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,WAAW,CAAC;AAcjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAa3D,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,WAghB/E"}
@@ -1,11 +1,12 @@
1
1
  import { EthAddress } from '@aztec/foundation/eth-address';
2
- import { withoutHexPrefix } from '@aztec/foundation/string';
3
2
  import { Option } from 'commander';
3
+ import { getL1RollupAddressFromEnv } from '../../config/get_l1_config.js';
4
4
  import { ETHEREUM_HOSTS, MNEMONIC, PRIVATE_KEY, l1ChainIdOption, parseAztecAddress, parseBigint, parseEthereumAddress, pxeOption } from '../../utils/commands.js';
5
5
  export { addL1Validator } from './update_l1_validators.js';
6
6
  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([
7
7
  ETHEREUM_HOSTS
8
8
  ]).makeOptionMandatory(true).argParser((arg)=>arg.split(',').map((url)=>url.trim()));
9
+ const networkOption = new Option('--network <string>', 'Network to execute against').env('NETWORK');
9
10
  export function injectCommands(program, log, debugLogger) {
10
11
  program.command('deploy-l1-contracts').description('Deploys all necessary Ethereum contracts for Aztec.').addOption(l1RpcUrlsOption).option('-pk, --private-key <string>', 'The private key to use for deployment', PRIVATE_KEY).option('--validators <string>', 'Comma separated list of validators').option('-m, --mnemonic <string>', 'The mnemonic to use in deployment', 'test test test test test test test test test test test junk').option('-i, --mnemonic-index <number>', 'The index of the mnemonic to use in deployment', (arg)=>parseInt(arg), 0).addOption(l1ChainIdOption).option('--salt <number>', 'The optional salt to use in deployment', (arg)=>parseInt(arg)).option('--json', 'Output the contract addresses in JSON format').option('--test-accounts', 'Populate genesis state with initial fee juice for test accounts').option('--sponsored-fpc', 'Populate genesis state with a testing sponsored FPC contract').option('--accelerated-test-deployments', 'Fire and forget deployment transactions, use in testing only', false).option('--real-verifier', 'Deploy the real verifier', false).option('--create-verification-json [path]', 'Create JSON file for etherscan contract verification', false).action(async (options)=>{
11
12
  const { deployL1Contracts } = await import('./deploy_l1_contracts.js');
@@ -95,18 +96,19 @@ export function injectCommands(program, log, debugLogger) {
95
96
  const account = generateL1Account();
96
97
  log(JSON.stringify(account, null, 2));
97
98
  });
98
- program.command('add-l1-validator').description('Adds a validator to the L1 rollup contract.').addOption(l1RpcUrlsOption).option('-pk, --private-key <string>', 'The private key to use sending the transaction', PRIVATE_KEY).option('-m, --mnemonic <string>', 'The mnemonic to use sending the transaction', 'test test test test test test test test test test test junk').addOption(l1ChainIdOption).option('--attester <address>', 'ethereum address of the attester', parseEthereumAddress).option('--bls-secret-key <string>', 'The BN254 scalar field element used as a secret key for BLS signatures. Will be associated with the attester address.', parseBigint).option('--staking-asset-handler <address>', 'ethereum address of the staking asset handler', parseEthereumAddress).option('--proof <buffer>', 'The proof to use for the attestation', (arg)=>Buffer.from(withoutHexPrefix(arg), 'hex')).option('--merkle-proof <string>', 'The merkle proof to use for the attestation (comma separated list of 32 byte buffers)', (arg)=>arg.split(',')).action(async (options)=>{
99
- const { addL1Validator } = await import('./update_l1_validators.js');
100
- await addL1Validator({
99
+ program.command('add-l1-validator').description('Adds a validator to the L1 rollup contract via a direct deposit.').addOption(l1RpcUrlsOption).addOption(networkOption).option('-pk, --private-key <string>', 'The private key to use sending the transaction', PRIVATE_KEY).option('-m, --mnemonic <string>', 'The mnemonic to use sending the transaction', 'test test test test test test test test test test test junk').addOption(l1ChainIdOption).option('--attester <address>', 'ethereum address of the attester', parseEthereumAddress).option('--withdrawer <address>', 'ethereum address of the withdrawer', parseEthereumAddress).option('--bls-secret-key <string>', 'The BN254 scalar field element used as a secret key for BLS signatures. Will be associated with the attester address.', parseBigint).option('--move-with-latest-rollup', 'Whether to move with the latest rollup', true).option('--rollup <string>', 'Rollup contract address', parseEthereumAddress).action(async (options)=>{
100
+ const { addL1ValidatorViaRollup } = await import('./update_l1_validators.js');
101
+ const rollupAddress = options.rollup ?? await getL1RollupAddressFromEnv(options.l1RpcUrls, options.l1ChainId);
102
+ await addL1ValidatorViaRollup({
101
103
  rpcUrls: options.l1RpcUrls,
102
104
  chainId: options.l1ChainId,
103
105
  privateKey: options.privateKey,
104
106
  mnemonic: options.mnemonic,
105
107
  attesterAddress: options.attester,
106
- stakingAssetHandlerAddress: options.stakingAssetHandler,
107
- merkleProof: options.merkleProof,
108
- proofParams: options.proof,
109
108
  blsSecretKey: options.blsSecretKey,
109
+ withdrawerAddress: options.withdrawer,
110
+ rollupAddress,
111
+ moveWithLatestRollup: options.moveWithLatestRollup,
110
112
  log,
111
113
  debugLogger
112
114
  });
@@ -29,6 +29,11 @@ export declare function addL1Validator({ rpcUrls, chainId, privateKey, mnemonic,
29
29
  proofParams: Buffer;
30
30
  merkleProof: string[];
31
31
  }): Promise<void>;
32
+ export declare function addL1ValidatorViaRollup({ rpcUrls, chainId, privateKey, mnemonic, attesterAddress, withdrawerAddress, blsSecretKey, moveWithLatestRollup, rollupAddress, log, debugLogger, }: RollupCommandArgs & LoggerArgs & {
33
+ blsSecretKey: bigint;
34
+ attesterAddress: EthAddress;
35
+ moveWithLatestRollup: boolean;
36
+ }): Promise<void>;
32
37
  export declare function removeL1Validator({ rpcUrls, chainId, privateKey, mnemonic, validatorAddress, rollupAddress, log, debugLogger, }: RollupCommandArgs & LoggerArgs & {
33
38
  validatorAddress: EthAddress;
34
39
  }): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"update_l1_validators.d.ts","sourceRoot":"","sources":["../../../src/cmds/l1/update_l1_validators.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAS3D,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;;;EAQhC;AAED,wBAAsB,cAAc,CAAC,EACnC,OAAO,EACP,OAAO,EACP,UAAU,EACV,QAAQ,EACR,eAAe,EACf,0BAA0B,EAC1B,WAAW,EACX,WAAW,EACX,YAAY,EACZ,GAAG,EACH,WAAW,GACZ,EAAE,8BAA8B,GAC/B,UAAU,GAAG;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,UAAU,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,iBA4DF;AAED,wBAAsB,iBAAiB,CAAC,EACtC,OAAO,EACP,OAAO,EACP,UAAU,EACV,QAAQ,EACR,gBAAgB,EAChB,aAAa,EACb,GAAG,EACH,WAAW,GACZ,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,GACZ,EAAE,iBAAiB,GAAG,UAAU,iBAgBhC;AAED,wBAAsB,iBAAiB,CAAC,EACtC,OAAO,EACP,OAAO,EACP,aAAa,EACb,SAAS,EACT,GAAG,EACH,WAAW,GACZ,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":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAS3D,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;;;EAQhC;AAED,wBAAsB,cAAc,CAAC,EACnC,OAAO,EACP,OAAO,EACP,UAAU,EACV,QAAQ,EACR,eAAe,EACf,0BAA0B,EAC1B,WAAW,EACX,WAAW,EACX,YAAY,EACZ,GAAG,EACH,WAAW,GACZ,EAAE,8BAA8B,GAC/B,UAAU,GAAG;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,UAAU,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,iBA4DF;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,GACZ,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,GACZ,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,GACZ,EAAE,iBAAiB,GAAG,UAAU,iBAgBhC;AAED,wBAAsB,iBAAiB,CAAC,EACtC,OAAO,EACP,OAAO,EACP,aAAa,EACb,SAAS,EACT,GAAG,EACH,WAAW,GACZ,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"}
@@ -71,6 +71,58 @@ export async function addL1Validator({ rpcUrls, chainId, privateKey, mnemonic, a
71
71
  }
72
72
  }
73
73
  }
74
+ export async function addL1ValidatorViaRollup({ rpcUrls, chainId, privateKey, mnemonic, attesterAddress, withdrawerAddress, blsSecretKey, moveWithLatestRollup, rollupAddress, log, debugLogger }) {
75
+ const dualLog = makeDualLog(log, debugLogger);
76
+ const account = getAccount(privateKey, mnemonic);
77
+ const chain = createEthereumChain(rpcUrls, chainId);
78
+ const l1Client = createExtendedL1Client(rpcUrls, account, chain.chainInfo);
79
+ dualLog(`Adding validator ${attesterAddress} to rollup ${rollupAddress.toString()} via direct deposit`);
80
+ if (!withdrawerAddress) {
81
+ throw new Error(`Withdrawer address required`);
82
+ }
83
+ const rollup = getContract({
84
+ address: rollupAddress.toString(),
85
+ abi: RollupAbi,
86
+ client: l1Client
87
+ });
88
+ const gseAddress = await rollup.read.getGSE();
89
+ const gse = new GSEContract(l1Client, gseAddress);
90
+ const registrationTuple = await gse.makeRegistrationTuple(blsSecretKey);
91
+ const l1TxUtils = createL1TxUtilsFromViemWallet(l1Client, debugLogger);
92
+ const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
93
+ to: rollupAddress.toString(),
94
+ data: encodeFunctionData({
95
+ abi: RollupAbi,
96
+ functionName: 'deposit',
97
+ args: [
98
+ attesterAddress.toString(),
99
+ withdrawerAddress.toString(),
100
+ registrationTuple.publicKeyInG1,
101
+ registrationTuple.publicKeyInG2,
102
+ registrationTuple.proofOfPossession,
103
+ moveWithLatestRollup
104
+ ]
105
+ }),
106
+ abi: StakingAssetHandlerAbi
107
+ });
108
+ dualLog(`Transaction hash: ${receipt.transactionHash}`);
109
+ await l1Client.waitForTransactionReceipt({
110
+ hash: receipt.transactionHash
111
+ });
112
+ if (isAnvilTestChain(chainId)) {
113
+ dualLog(`Funding validator on L1`);
114
+ const cheatCodes = new EthCheatCodes(rpcUrls, debugLogger);
115
+ await cheatCodes.setBalance(attesterAddress, 10n ** 20n);
116
+ } else {
117
+ const balance = await l1Client.getBalance({
118
+ address: attesterAddress.toString()
119
+ });
120
+ dualLog(`Validator balance: ${formatEther(balance)} ETH`);
121
+ if (balance === 0n) {
122
+ dualLog(`WARNING: Proposer has no balance. Remember to fund it!`);
123
+ }
124
+ }
125
+ }
74
126
  export async function removeL1Validator({ rpcUrls, chainId, privateKey, mnemonic, validatorAddress, rollupAddress, log, debugLogger }) {
75
127
  const dualLog = makeDualLog(log, debugLogger);
76
128
  const account = getAccount(privateKey, mnemonic);
@@ -0,0 +1,32 @@
1
+ import { type L1ContractsConfig } from '@aztec/ethereum';
2
+ import type { NetworkNames } from '@aztec/foundation/config';
3
+ import type { SharedNodeConfig } from '@aztec/node-lib/config';
4
+ import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
5
+ export type L2ChainConfig = L1ContractsConfig & Omit<SlasherConfig, 'slashValidatorsNever' | 'slashValidatorsAlways'> & {
6
+ l1ChainId: number;
7
+ testAccounts: boolean;
8
+ sponsoredFPC: boolean;
9
+ p2pEnabled: boolean;
10
+ p2pBootstrapNodes: string[];
11
+ registryAddress: string;
12
+ slashFactoryAddress: string;
13
+ feeAssetHandlerAddress: string;
14
+ seqMinTxsPerBlock: number;
15
+ seqMaxTxsPerBlock: number;
16
+ realProofs: boolean;
17
+ snapshotsUrl: string;
18
+ autoUpdate: SharedNodeConfig['autoUpdate'];
19
+ autoUpdateUrl?: string;
20
+ maxTxPoolSize: number;
21
+ publicIncludeMetrics?: string[];
22
+ publicMetricsCollectorUrl?: string;
23
+ publicMetricsCollectFrom?: string[];
24
+ sentinelEnabled: boolean;
25
+ };
26
+ export declare const stagingIgnitionL2ChainConfig: L2ChainConfig;
27
+ export declare const stagingPublicL2ChainConfig: L2ChainConfig;
28
+ export declare const testnetL2ChainConfig: L2ChainConfig;
29
+ export declare function getBootnodes(networkName: NetworkNames, cacheDir?: string): Promise<any>;
30
+ export declare function getL2ChainConfig(networkName: NetworkNames, cacheDir?: string): Promise<L2ChainConfig | undefined>;
31
+ export declare function enrichEnvironmentWithChainConfig(networkName: NetworkNames): Promise<void>;
32
+ //# sourceMappingURL=chain_l2_config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain_l2_config.d.ts","sourceRoot":"","sources":["../../src/config/chain_l2_config.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACnF,OAAO,KAAK,EAAU,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAOrE,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAC3C,IAAI,CAAC,aAAa,EAAE,sBAAsB,GAAG,uBAAuB,CAAC,GAAG;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;IAGpC,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEJ,eAAO,MAAM,4BAA4B,EAAE,aAwD1C,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,aA4ExC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,aA4ElC,CAAC;AAIF,wBAAsB,YAAY,CAAC,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,MAAM,gBAgC9E;AAED,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,YAAY,EACzB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAkBpC;AAuBD,wBAAsB,gCAAgC,CAAC,WAAW,EAAE,YAAY,iBAyF/E"}
@@ -0,0 +1,326 @@
1
+ import { DefaultL1ContractsConfig } from '@aztec/ethereum';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+ import { mkdir, readFile, stat, writeFile } from 'fs/promises';
4
+ import path, { dirname, join } from 'path';
5
+ import publicIncludeMetrics from '../../public_include_metric_prefixes.json' with {
6
+ type: 'json'
7
+ };
8
+ export const stagingIgnitionL2ChainConfig = {
9
+ l1ChainId: 11155111,
10
+ testAccounts: true,
11
+ sponsoredFPC: false,
12
+ p2pEnabled: true,
13
+ p2pBootstrapNodes: [],
14
+ registryAddress: '0xf299347e765cfb27f913bde8e4983fd0f195676f',
15
+ slashFactoryAddress: '',
16
+ feeAssetHandlerAddress: '',
17
+ seqMinTxsPerBlock: 0,
18
+ seqMaxTxsPerBlock: 0,
19
+ realProofs: true,
20
+ snapshotsUrl: 'https://storage.googleapis.com/aztec-testnet/snapshots/staging-ignition/',
21
+ autoUpdate: 'config-and-version',
22
+ autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/staging-ignition.json',
23
+ maxTxPoolSize: 100_000_000,
24
+ publicIncludeMetrics,
25
+ publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
26
+ publicMetricsCollectFrom: [
27
+ 'sequencer'
28
+ ],
29
+ ...DefaultL1ContractsConfig,
30
+ /** How many seconds an L1 slot lasts. */ ethereumSlotDuration: 12,
31
+ /** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */ aztecSlotDuration: 36,
32
+ /** How many L2 slots an epoch lasts. */ aztecEpochDuration: 32,
33
+ /** The target validator committee size. */ aztecTargetCommitteeSize: 48,
34
+ /** The number of epochs after an epoch ends that proofs are still accepted. */ aztecProofSubmissionEpochs: 1,
35
+ /** The mana target for the rollup */ manaTarget: 0n,
36
+ /** The proving cost per mana */ provingCostPerMana: 0n,
37
+ slasherFlavor: 'none',
38
+ slashAmountSmall: 0n,
39
+ slashAmountMedium: 0n,
40
+ slashAmountLarge: 0n,
41
+ slashMinPenaltyPercentage: 0.5,
42
+ slashMaxPenaltyPercentage: 200,
43
+ slashInactivityTargetPercentage: 0,
44
+ slashInactivityConsecutiveEpochThreshold: 1,
45
+ slashInactivityPenalty: 0n,
46
+ slashPrunePenalty: 0n,
47
+ slashDataWithholdingPenalty: 0n,
48
+ slashProposeInvalidAttestationsPenalty: 0n,
49
+ slashAttestDescendantOfInvalidPenalty: 0n,
50
+ slashBroadcastedInvalidBlockPenalty: 0n,
51
+ slashMaxPayloadSize: 50,
52
+ slashGracePeriodL2Slots: 0,
53
+ slashUnknownPenalty: 0n,
54
+ slashOffenseExpirationRounds: 10,
55
+ sentinelEnabled: false
56
+ };
57
+ export const stagingPublicL2ChainConfig = {
58
+ l1ChainId: 11155111,
59
+ testAccounts: false,
60
+ sponsoredFPC: true,
61
+ p2pEnabled: true,
62
+ p2pBootstrapNodes: [],
63
+ registryAddress: '0x2e48addca360da61e4d6c21ff2b1961af56eb83b',
64
+ slashFactoryAddress: '0xe19410632fd00695bc5a08dd82044b7b26317742',
65
+ feeAssetHandlerAddress: '0xb46dc3d91f849999330b6dd93473fa29fc45b076',
66
+ seqMinTxsPerBlock: 0,
67
+ seqMaxTxsPerBlock: 20,
68
+ realProofs: true,
69
+ snapshotsUrl: 'https://storage.googleapis.com/aztec-testnet/snapshots/staging-public/',
70
+ autoUpdate: 'config-and-version',
71
+ autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/staging-public.json',
72
+ publicIncludeMetrics,
73
+ publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
74
+ publicMetricsCollectFrom: [
75
+ 'sequencer'
76
+ ],
77
+ maxTxPoolSize: 100_000_000,
78
+ // Deployment stuff
79
+ /** How many seconds an L1 slot lasts. */ ethereumSlotDuration: 12,
80
+ /** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */ aztecSlotDuration: 36,
81
+ /** How many L2 slots an epoch lasts. */ aztecEpochDuration: 32,
82
+ /** The target validator committee size. */ aztecTargetCommitteeSize: 48,
83
+ /** The number of epochs after an epoch ends that proofs are still accepted. */ aztecProofSubmissionEpochs: 1,
84
+ /** The deposit amount for a validator */ activationThreshold: DefaultL1ContractsConfig.activationThreshold,
85
+ /** The minimum stake for a validator. */ ejectionThreshold: DefaultL1ContractsConfig.ejectionThreshold,
86
+ /** The slashing round size */ slashingRoundSizeInEpochs: DefaultL1ContractsConfig.slashingRoundSizeInEpochs,
87
+ /** Governance proposing round size */ governanceProposerRoundSize: DefaultL1ContractsConfig.governanceProposerRoundSize,
88
+ /** The mana target for the rollup */ manaTarget: DefaultL1ContractsConfig.manaTarget,
89
+ /** The proving cost per mana */ provingCostPerMana: DefaultL1ContractsConfig.provingCostPerMana,
90
+ /** Exit delay for stakers */ exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
91
+ /** Tally-style slashing */ slasherFlavor: 'tally',
92
+ /** Allow one round for vetoing */ slashingExecutionDelayInRounds: 1,
93
+ /** How long for a slash payload to be executed */ slashingLifetimeInRounds: 5,
94
+ /** Allow 2 rounds to discover faults */ slashingOffsetInRounds: 2,
95
+ /** No slash vetoer */ slashingVetoer: EthAddress.ZERO,
96
+ /** Use default slash amounts */ slashAmountSmall: DefaultL1ContractsConfig.slashAmountSmall,
97
+ slashAmountMedium: DefaultL1ContractsConfig.slashAmountMedium,
98
+ slashAmountLarge: DefaultL1ContractsConfig.slashAmountLarge,
99
+ // Slashing stuff
100
+ slashMinPenaltyPercentage: 0.5,
101
+ slashMaxPenaltyPercentage: 2.0,
102
+ slashInactivityTargetPercentage: 0.7,
103
+ slashInactivityConsecutiveEpochThreshold: 1,
104
+ slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
105
+ slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
106
+ slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
107
+ slashProposeInvalidAttestationsPenalty: DefaultL1ContractsConfig.slashAmountLarge,
108
+ slashAttestDescendantOfInvalidPenalty: DefaultL1ContractsConfig.slashAmountLarge,
109
+ slashUnknownPenalty: DefaultL1ContractsConfig.slashAmountSmall,
110
+ slashBroadcastedInvalidBlockPenalty: DefaultL1ContractsConfig.slashAmountMedium,
111
+ slashMaxPayloadSize: 50,
112
+ slashGracePeriodL2Slots: 32 * 2,
113
+ slashOffenseExpirationRounds: 8,
114
+ sentinelEnabled: true
115
+ };
116
+ export const testnetL2ChainConfig = {
117
+ l1ChainId: 11155111,
118
+ testAccounts: false,
119
+ sponsoredFPC: true,
120
+ p2pEnabled: true,
121
+ p2pBootstrapNodes: [],
122
+ registryAddress: '0xcfe61b2574984326679cd15c6566fbd4a724f3b4',
123
+ slashFactoryAddress: '0x58dc5b14f9d3085c9106f5b8208a1026f94614f0',
124
+ feeAssetHandlerAddress: '0x7abdec6e68ae27c37feb6a77371382a109ec4763',
125
+ seqMinTxsPerBlock: 0,
126
+ seqMaxTxsPerBlock: 20,
127
+ realProofs: true,
128
+ snapshotsUrl: 'https://storage.googleapis.com/aztec-testnet/snapshots/testnet/',
129
+ autoUpdate: 'config-and-version',
130
+ autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/testnet.json',
131
+ maxTxPoolSize: 100_000_000,
132
+ publicIncludeMetrics,
133
+ publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
134
+ publicMetricsCollectFrom: [
135
+ 'sequencer'
136
+ ],
137
+ // Deployment stuff
138
+ /** How many seconds an L1 slot lasts. */ ethereumSlotDuration: 12,
139
+ /** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */ aztecSlotDuration: 36,
140
+ /** How many L2 slots an epoch lasts. */ aztecEpochDuration: 32,
141
+ /** The target validator committee size. */ aztecTargetCommitteeSize: 48,
142
+ /** The number of epochs after an epoch ends that proofs are still accepted. */ aztecProofSubmissionEpochs: 1,
143
+ /** The deposit amount for a validator */ activationThreshold: DefaultL1ContractsConfig.activationThreshold,
144
+ /** The minimum stake for a validator. */ ejectionThreshold: DefaultL1ContractsConfig.ejectionThreshold,
145
+ /** The slashing round size */ slashingRoundSizeInEpochs: DefaultL1ContractsConfig.slashingRoundSizeInEpochs,
146
+ /** Governance proposing round size */ governanceProposerRoundSize: DefaultL1ContractsConfig.governanceProposerRoundSize,
147
+ /** The mana target for the rollup */ manaTarget: DefaultL1ContractsConfig.manaTarget,
148
+ /** The proving cost per mana */ provingCostPerMana: DefaultL1ContractsConfig.provingCostPerMana,
149
+ /** Exit delay for stakers */ exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
150
+ /** Tally-style slashing */ slasherFlavor: 'tally',
151
+ /** Allow one round for vetoing */ slashingExecutionDelayInRounds: 1,
152
+ /** How long for a slash payload to be executed */ slashingLifetimeInRounds: 5,
153
+ /** Allow 2 rounds to discover faults */ slashingOffsetInRounds: 2,
154
+ /** No slash vetoer */ slashingVetoer: EthAddress.ZERO,
155
+ /** Use default slash amounts */ slashAmountSmall: DefaultL1ContractsConfig.slashAmountSmall,
156
+ slashAmountMedium: DefaultL1ContractsConfig.slashAmountMedium,
157
+ slashAmountLarge: DefaultL1ContractsConfig.slashAmountLarge,
158
+ // Slashing stuff
159
+ slashMinPenaltyPercentage: 0.5,
160
+ slashMaxPenaltyPercentage: 2.0,
161
+ slashInactivityTargetPercentage: 0.7,
162
+ slashInactivityConsecutiveEpochThreshold: 1,
163
+ slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
164
+ slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
165
+ slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
166
+ slashProposeInvalidAttestationsPenalty: DefaultL1ContractsConfig.slashAmountLarge,
167
+ slashAttestDescendantOfInvalidPenalty: DefaultL1ContractsConfig.slashAmountLarge,
168
+ slashUnknownPenalty: DefaultL1ContractsConfig.slashAmountSmall,
169
+ slashBroadcastedInvalidBlockPenalty: DefaultL1ContractsConfig.slashAmountMedium,
170
+ slashMaxPayloadSize: 50,
171
+ slashGracePeriodL2Slots: 32 * 2,
172
+ slashOffenseExpirationRounds: 8,
173
+ sentinelEnabled: true
174
+ };
175
+ const BOOTNODE_CACHE_DURATION_MS = 60 * 60 * 1000; // 1 hour;
176
+ export async function getBootnodes(networkName, cacheDir) {
177
+ const cacheFile = cacheDir ? join(cacheDir, networkName, 'bootnodes.json') : undefined;
178
+ try {
179
+ if (cacheFile) {
180
+ const info = await stat(cacheFile);
181
+ if (info.mtimeMs + BOOTNODE_CACHE_DURATION_MS > Date.now()) {
182
+ return JSON.parse(await readFile(cacheFile, 'utf-8'))['bootnodes'];
183
+ }
184
+ }
185
+ } catch {
186
+ // no-op. Get the remote-file
187
+ }
188
+ const url = `http://static.aztec.network/${networkName}/bootnodes.json`;
189
+ const response = await fetch(url);
190
+ if (!response.ok) {
191
+ throw new Error(`Failed to fetch basic contract addresses from ${url}. Check you are using a correct network name.`);
192
+ }
193
+ const json = await response.json();
194
+ try {
195
+ if (cacheFile) {
196
+ await mkdir(dirname(cacheFile), {
197
+ recursive: true
198
+ });
199
+ await writeFile(cacheFile, JSON.stringify(json), 'utf-8');
200
+ }
201
+ } catch {
202
+ // no-op
203
+ }
204
+ return json['bootnodes'];
205
+ }
206
+ export async function getL2ChainConfig(networkName, cacheDir) {
207
+ let config;
208
+ if (networkName === 'staging-public') {
209
+ config = {
210
+ ...stagingPublicL2ChainConfig
211
+ };
212
+ } else if (networkName === 'testnet') {
213
+ config = {
214
+ ...testnetL2ChainConfig
215
+ };
216
+ } else if (networkName === 'staging-ignition') {
217
+ config = {
218
+ ...stagingIgnitionL2ChainConfig
219
+ };
220
+ }
221
+ if (!config) {
222
+ return undefined;
223
+ }
224
+ // If the bootnodes are not set, get them from the network
225
+ const bootnodeKey = 'BOOTSTRAP_NODES';
226
+ if (!process.env[bootnodeKey]) {
227
+ config.p2pBootstrapNodes = await getBootnodes(networkName, cacheDir);
228
+ }
229
+ return config;
230
+ }
231
+ function enrichVar(envVar, value) {
232
+ // Don't override
233
+ if (process.env[envVar] || value === undefined) {
234
+ return;
235
+ }
236
+ process.env[envVar] = value;
237
+ }
238
+ function enrichEthAddressVar(envVar, value) {
239
+ // EthAddress doesn't like being given empty strings
240
+ if (value === '') {
241
+ enrichVar(envVar, EthAddress.ZERO.toString());
242
+ return;
243
+ }
244
+ enrichVar(envVar, value);
245
+ }
246
+ function getDefaultDataDir(networkName) {
247
+ return path.join(process.env.HOME || '~', '.aztec', networkName, 'data');
248
+ }
249
+ export async function enrichEnvironmentWithChainConfig(networkName) {
250
+ if (networkName === 'local') {
251
+ return;
252
+ }
253
+ enrichVar('DATA_DIRECTORY', getDefaultDataDir(networkName));
254
+ const cacheDir = process.env.DATA_DIRECTORY ? join(process.env.DATA_DIRECTORY, 'cache') : undefined;
255
+ const config = await getL2ChainConfig(networkName, cacheDir);
256
+ if (!config) {
257
+ throw new Error(`Unknown network name: ${networkName}`);
258
+ }
259
+ enrichVar('BOOTSTRAP_NODES', config.p2pBootstrapNodes.join(','));
260
+ enrichVar('TEST_ACCOUNTS', config.testAccounts.toString());
261
+ enrichVar('SPONSORED_FPC', config.sponsoredFPC.toString());
262
+ enrichVar('P2P_ENABLED', config.p2pEnabled.toString());
263
+ enrichVar('L1_CHAIN_ID', config.l1ChainId.toString());
264
+ enrichVar('SEQ_MIN_TX_PER_BLOCK', config.seqMinTxsPerBlock.toString());
265
+ enrichVar('SEQ_MAX_TX_PER_BLOCK', config.seqMaxTxsPerBlock.toString());
266
+ enrichVar('PROVER_REAL_PROOFS', config.realProofs.toString());
267
+ enrichVar('PXE_PROVER_ENABLED', config.realProofs.toString());
268
+ enrichVar('SYNC_SNAPSHOTS_URL', config.snapshotsUrl);
269
+ enrichVar('P2P_MAX_TX_POOL_SIZE', config.maxTxPoolSize.toString());
270
+ if (config.autoUpdate) {
271
+ enrichVar('AUTO_UPDATE', config.autoUpdate?.toString());
272
+ }
273
+ if (config.autoUpdateUrl) {
274
+ enrichVar('AUTO_UPDATE_URL', config.autoUpdateUrl);
275
+ }
276
+ if (config.publicIncludeMetrics) {
277
+ enrichVar('PUBLIC_OTEL_INCLUDE_METRICS', config.publicIncludeMetrics.join(','));
278
+ }
279
+ if (config.publicMetricsCollectorUrl) {
280
+ enrichVar('PUBLIC_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT', config.publicMetricsCollectorUrl);
281
+ }
282
+ if (config.publicMetricsCollectFrom) {
283
+ enrichVar('PUBLIC_OTEL_COLLECT_FROM', config.publicMetricsCollectFrom.join(','));
284
+ }
285
+ enrichEthAddressVar('REGISTRY_CONTRACT_ADDRESS', config.registryAddress);
286
+ enrichEthAddressVar('SLASH_FACTORY_CONTRACT_ADDRESS', config.slashFactoryAddress);
287
+ enrichEthAddressVar('FEE_ASSET_HANDLER_CONTRACT_ADDRESS', config.feeAssetHandlerAddress);
288
+ // Deployment stuff
289
+ enrichVar('ETHEREUM_SLOT_DURATION', config.ethereumSlotDuration.toString());
290
+ enrichVar('AZTEC_SLOT_DURATION', config.aztecSlotDuration.toString());
291
+ enrichVar('AZTEC_EPOCH_DURATION', config.aztecEpochDuration.toString());
292
+ enrichVar('AZTEC_TARGET_COMMITTEE_SIZE', config.aztecTargetCommitteeSize.toString());
293
+ enrichVar('AZTEC_PROOF_SUBMISSION_EPOCHS', config.aztecProofSubmissionEpochs.toString());
294
+ enrichVar('AZTEC_ACTIVATION_THRESHOLD', config.activationThreshold.toString());
295
+ enrichVar('AZTEC_EJECTION_THRESHOLD', config.ejectionThreshold.toString());
296
+ enrichVar('AZTEC_SLASHING_QUORUM', config.slashingQuorum?.toString());
297
+ enrichVar('AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS', config.slashingRoundSizeInEpochs.toString());
298
+ enrichVar('AZTEC_GOVERNANCE_PROPOSER_QUORUM', config.governanceProposerQuorum?.toString());
299
+ enrichVar('AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE', config.governanceProposerRoundSize.toString());
300
+ enrichVar('AZTEC_MANA_TARGET', config.manaTarget.toString());
301
+ enrichVar('AZTEC_PROVING_COST_PER_MANA', config.provingCostPerMana.toString());
302
+ enrichVar('AZTEC_SLASH_AMOUNT_SMALL', config.slashAmountSmall.toString());
303
+ enrichVar('AZTEC_SLASH_AMOUNT_MEDIUM', config.slashAmountMedium.toString());
304
+ enrichVar('AZTEC_SLASH_AMOUNT_LARGE', config.slashAmountLarge.toString());
305
+ enrichVar('AZTEC_SLASHING_LIFETIME_IN_ROUNDS', config.slashingLifetimeInRounds.toString());
306
+ enrichVar('AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS', config.slashingExecutionDelayInRounds.toString());
307
+ enrichVar('AZTEC_SLASHING_OFFSET_IN_ROUNDS', config.slashingOffsetInRounds.toString());
308
+ enrichVar('AZTEC_SLASHER_FLAVOR', config.slasherFlavor);
309
+ enrichVar('AZTEC_EXIT_DELAY_SECONDS', config.exitDelaySeconds.toString());
310
+ enrichEthAddressVar('AZTEC_SLASHING_VETOER', config.slashingVetoer.toString());
311
+ // Slashing
312
+ enrichVar('SLASH_MIN_PENALTY_PERCENTAGE', config.slashMinPenaltyPercentage.toString());
313
+ enrichVar('SLASH_MAX_PENALTY_PERCENTAGE', config.slashMaxPenaltyPercentage.toString());
314
+ enrichVar('SLASH_PRUNE_PENALTY', config.slashPrunePenalty.toString());
315
+ enrichVar('SLASH_DATA_WITHHOLDING_PENALTY', config.slashDataWithholdingPenalty.toString());
316
+ enrichVar('SLASH_INACTIVITY_TARGET_PERCENTAGE', config.slashInactivityTargetPercentage.toString());
317
+ enrichVar('SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD', config.slashInactivityConsecutiveEpochThreshold.toString());
318
+ enrichVar('SLASH_INACTIVITY_PENALTY', config.slashInactivityPenalty.toString());
319
+ enrichVar('SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY', config.slashProposeInvalidAttestationsPenalty.toString());
320
+ enrichVar('SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY', config.slashAttestDescendantOfInvalidPenalty.toString());
321
+ enrichVar('SLASH_UNKNOWN_PENALTY', config.slashUnknownPenalty.toString());
322
+ enrichVar('SLASH_INVALID_BLOCK_PENALTY', config.slashBroadcastedInvalidBlockPenalty.toString());
323
+ enrichVar('SLASH_OFFENSE_EXPIRATION_ROUNDS', config.slashOffenseExpirationRounds.toString());
324
+ enrichVar('SLASH_MAX_PAYLOAD_SIZE', config.slashMaxPayloadSize.toString());
325
+ enrichVar('SENTINEL_ENABLED', config.sentinelEnabled.toString());
326
+ }
@@ -0,0 +1,8 @@
1
+ import { type L1ContractAddresses, getL1ContractsConfig } from '@aztec/ethereum';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+ export declare function getL1Config(registryAddress: EthAddress, l1RpcUrls: string[], l1ChainId: number, rollupVersion?: number | 'canonical'): Promise<{
4
+ addresses: L1ContractAddresses;
5
+ config: Awaited<ReturnType<typeof getL1ContractsConfig>>;
6
+ }>;
7
+ export declare function getL1RollupAddressFromEnv(l1RpcUrls: string[], l1ChainId: number): Promise<EthAddress>;
8
+ //# sourceMappingURL=get_l1_config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get_l1_config.d.ts","sourceRoot":"","sources":["../../src/config/get_l1_config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,mBAAmB,EAAoB,oBAAoB,EAAmB,MAAM,iBAAiB,CAAC;AACpH,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,wBAAsB,WAAW,CAC/B,eAAe,EAAE,UAAU,EAC3B,SAAS,EAAE,MAAM,EAAE,EACnB,SAAS,EAAE,MAAM,EACjB,aAAa,GAAE,MAAM,GAAG,WAAyB,GAChD,OAAO,CAAC;IAAE,SAAS,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAA;CAAE,CAAC,CAUvG;AAED,wBAAsB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,uBAOrF"}
@@ -0,0 +1,22 @@
1
+ import { RegistryContract, getL1ContractsConfig, getPublicClient } from '@aztec/ethereum';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+ export async function getL1Config(registryAddress, l1RpcUrls, l1ChainId, rollupVersion = 'canonical') {
4
+ const publicClient = getPublicClient({
5
+ l1RpcUrls,
6
+ l1ChainId
7
+ });
8
+ const addresses = await RegistryContract.collectAddresses(publicClient, registryAddress, rollupVersion);
9
+ const config = await getL1ContractsConfig(publicClient, addresses);
10
+ return {
11
+ addresses,
12
+ config
13
+ };
14
+ }
15
+ export async function getL1RollupAddressFromEnv(l1RpcUrls, l1ChainId) {
16
+ const registryAddress = process.env.REGISTRY_CONTRACT_ADDRESS;
17
+ if (!registryAddress || !EthAddress.isAddress(registryAddress)) {
18
+ throw new Error(`Failed to extract registry address`);
19
+ }
20
+ const { addresses } = await getL1Config(EthAddress.fromString(registryAddress), l1RpcUrls, l1ChainId);
21
+ return addresses.rollupAddress;
22
+ }
@@ -0,0 +1,3 @@
1
+ export * from './chain_l2_config.js';
2
+ export * from './get_l1_config.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './chain_l2_config.js';
2
+ export * from './get_l1_config.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/cli",
3
- "version": "3.0.0-nightly.20250908",
3
+ "version": "3.0.0-nightly.20250910",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./contracts": "./dest/cmds/contracts/index.js",
@@ -12,7 +12,8 @@
12
12
  "./misc": "./dest/cmds/misc/index.js",
13
13
  "./setup-contracts": "./dest/cmds/misc/setup_contracts.js",
14
14
  "./utils": "./dest/utils/index.js",
15
- "./inspect": "./dest/utils/inspect.js"
15
+ "./inspect": "./dest/utils/inspect.js",
16
+ "./config": "./dest/config/index.js"
16
17
  },
17
18
  "typedocOptions": {
18
19
  "entryPoints": [
@@ -69,16 +70,17 @@
69
70
  ]
70
71
  },
71
72
  "dependencies": {
72
- "@aztec/archiver": "3.0.0-nightly.20250908",
73
- "@aztec/aztec.js": "3.0.0-nightly.20250908",
74
- "@aztec/constants": "3.0.0-nightly.20250908",
75
- "@aztec/entrypoints": "3.0.0-nightly.20250908",
76
- "@aztec/ethereum": "3.0.0-nightly.20250908",
77
- "@aztec/foundation": "3.0.0-nightly.20250908",
78
- "@aztec/l1-artifacts": "3.0.0-nightly.20250908",
79
- "@aztec/p2p": "3.0.0-nightly.20250908",
80
- "@aztec/stdlib": "3.0.0-nightly.20250908",
81
- "@aztec/world-state": "3.0.0-nightly.20250908",
73
+ "@aztec/archiver": "3.0.0-nightly.20250910",
74
+ "@aztec/aztec.js": "3.0.0-nightly.20250910",
75
+ "@aztec/constants": "3.0.0-nightly.20250910",
76
+ "@aztec/entrypoints": "3.0.0-nightly.20250910",
77
+ "@aztec/ethereum": "3.0.0-nightly.20250910",
78
+ "@aztec/foundation": "3.0.0-nightly.20250910",
79
+ "@aztec/l1-artifacts": "3.0.0-nightly.20250910",
80
+ "@aztec/node-lib": "3.0.0-nightly.20250910",
81
+ "@aztec/p2p": "3.0.0-nightly.20250910",
82
+ "@aztec/stdlib": "3.0.0-nightly.20250910",
83
+ "@aztec/world-state": "3.0.0-nightly.20250910",
82
84
  "@iarna/toml": "^2.2.5",
83
85
  "@libp2p/peer-id-factory": "^3.0.4",
84
86
  "commander": "^12.1.0",
@@ -90,8 +92,8 @@
90
92
  "viem": "2.23.7"
91
93
  },
92
94
  "devDependencies": {
93
- "@aztec/accounts": "3.0.0-nightly.20250908",
94
- "@aztec/protocol-contracts": "3.0.0-nightly.20250908",
95
+ "@aztec/accounts": "3.0.0-nightly.20250910",
96
+ "@aztec/protocol-contracts": "3.0.0-nightly.20250910",
95
97
  "@jest/globals": "^30.0.0",
96
98
  "@types/jest": "^30.0.0",
97
99
  "@types/lodash.chunk": "^4.2.9",
@@ -107,15 +109,15 @@
107
109
  "typescript": "^5.3.3"
108
110
  },
109
111
  "peerDependencies": {
110
- "@aztec/accounts": "3.0.0-nightly.20250908",
111
- "@aztec/bb-prover": "3.0.0-nightly.20250908",
112
- "@aztec/ethereum": "3.0.0-nightly.20250908",
113
- "@aztec/l1-artifacts": "3.0.0-nightly.20250908",
114
- "@aztec/noir-contracts.js": "3.0.0-nightly.20250908",
115
- "@aztec/noir-protocol-circuits-types": "3.0.0-nightly.20250908",
116
- "@aztec/noir-test-contracts.js": "3.0.0-nightly.20250908",
117
- "@aztec/protocol-contracts": "3.0.0-nightly.20250908",
118
- "@aztec/stdlib": "3.0.0-nightly.20250908"
112
+ "@aztec/accounts": "3.0.0-nightly.20250910",
113
+ "@aztec/bb-prover": "3.0.0-nightly.20250910",
114
+ "@aztec/ethereum": "3.0.0-nightly.20250910",
115
+ "@aztec/l1-artifacts": "3.0.0-nightly.20250910",
116
+ "@aztec/noir-contracts.js": "3.0.0-nightly.20250910",
117
+ "@aztec/noir-protocol-circuits-types": "3.0.0-nightly.20250910",
118
+ "@aztec/noir-test-contracts.js": "3.0.0-nightly.20250910",
119
+ "@aztec/protocol-contracts": "3.0.0-nightly.20250910",
120
+ "@aztec/stdlib": "3.0.0-nightly.20250910"
119
121
  },
120
122
  "files": [
121
123
  "dest",
@@ -1,9 +1,9 @@
1
1
  import { EthAddress } from '@aztec/foundation/eth-address';
2
2
  import type { LogFn, Logger } from '@aztec/foundation/log';
3
- import { withoutHexPrefix } from '@aztec/foundation/string';
4
3
 
5
4
  import { type Command, Option } from 'commander';
6
5
 
6
+ import { getL1RollupAddressFromEnv } from '../../config/get_l1_config.js';
7
7
  import {
8
8
  ETHEREUM_HOSTS,
9
9
  MNEMONIC,
@@ -26,6 +26,8 @@ const l1RpcUrlsOption = new Option(
26
26
  .makeOptionMandatory(true)
27
27
  .argParser((arg: string) => arg.split(',').map(url => url.trim()));
28
28
 
29
+ const networkOption = new Option('--network <string>', 'Network to execute against').env('NETWORK');
30
+
29
31
  export function injectCommands(program: Command, log: LogFn, debugLogger: Logger) {
30
32
  program
31
33
  .command('deploy-l1-contracts')
@@ -285,8 +287,9 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger
285
287
 
286
288
  program
287
289
  .command('add-l1-validator')
288
- .description('Adds a validator to the L1 rollup contract.')
290
+ .description('Adds a validator to the L1 rollup contract via a direct deposit.')
289
291
  .addOption(l1RpcUrlsOption)
292
+ .addOption(networkOption)
290
293
  .option('-pk, --private-key <string>', 'The private key to use sending the transaction', PRIVATE_KEY)
291
294
  .option(
292
295
  '-m, --mnemonic <string>',
@@ -295,32 +298,29 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger
295
298
  )
296
299
  .addOption(l1ChainIdOption)
297
300
  .option('--attester <address>', 'ethereum address of the attester', parseEthereumAddress)
301
+ .option('--withdrawer <address>', 'ethereum address of the withdrawer', parseEthereumAddress)
298
302
  .option(
299
303
  '--bls-secret-key <string>',
300
304
  'The BN254 scalar field element used as a secret key for BLS signatures. Will be associated with the attester address.',
301
305
  parseBigint,
302
306
  )
303
- .option('--staking-asset-handler <address>', 'ethereum address of the staking asset handler', parseEthereumAddress)
304
- .option('--proof <buffer>', 'The proof to use for the attestation', arg =>
305
- Buffer.from(withoutHexPrefix(arg), 'hex'),
306
- )
307
- .option(
308
- '--merkle-proof <string>',
309
- 'The merkle proof to use for the attestation (comma separated list of 32 byte buffers)',
310
- arg => arg.split(','),
311
- )
307
+ .option('--move-with-latest-rollup', 'Whether to move with the latest rollup', true)
308
+ .option('--rollup <string>', 'Rollup contract address', parseEthereumAddress)
312
309
  .action(async options => {
313
- const { addL1Validator } = await import('./update_l1_validators.js');
314
- await addL1Validator({
310
+ const { addL1ValidatorViaRollup } = await import('./update_l1_validators.js');
311
+
312
+ const rollupAddress = options.rollup ?? (await getL1RollupAddressFromEnv(options.l1RpcUrls, options.l1ChainId));
313
+
314
+ await addL1ValidatorViaRollup({
315
315
  rpcUrls: options.l1RpcUrls,
316
316
  chainId: options.l1ChainId,
317
317
  privateKey: options.privateKey,
318
318
  mnemonic: options.mnemonic,
319
319
  attesterAddress: options.attester,
320
- stakingAssetHandlerAddress: options.stakingAssetHandler,
321
- merkleProof: options.merkleProof,
322
- proofParams: options.proof,
323
320
  blsSecretKey: options.blsSecretKey,
321
+ withdrawerAddress: options.withdrawer,
322
+ rollupAddress,
323
+ moveWithLatestRollup: options.moveWithLatestRollup,
324
324
  log,
325
325
  debugLogger,
326
326
  });
@@ -131,6 +131,80 @@ export async function addL1Validator({
131
131
  }
132
132
  }
133
133
 
134
+ export async function addL1ValidatorViaRollup({
135
+ rpcUrls,
136
+ chainId,
137
+ privateKey,
138
+ mnemonic,
139
+ attesterAddress,
140
+ withdrawerAddress,
141
+ blsSecretKey,
142
+ moveWithLatestRollup,
143
+ rollupAddress,
144
+ log,
145
+ debugLogger,
146
+ }: RollupCommandArgs &
147
+ LoggerArgs & {
148
+ blsSecretKey: bigint; // scalar field element of BN254
149
+ attesterAddress: EthAddress;
150
+ moveWithLatestRollup: boolean;
151
+ }) {
152
+ const dualLog = makeDualLog(log, debugLogger);
153
+ const account = getAccount(privateKey, mnemonic);
154
+ const chain = createEthereumChain(rpcUrls, chainId);
155
+ const l1Client = createExtendedL1Client(rpcUrls, account, chain.chainInfo);
156
+
157
+ dualLog(`Adding validator ${attesterAddress} to rollup ${rollupAddress.toString()} via direct deposit`);
158
+
159
+ if (!withdrawerAddress) {
160
+ throw new Error(`Withdrawer address required`);
161
+ }
162
+
163
+ const rollup = getContract({
164
+ address: rollupAddress.toString(),
165
+ abi: RollupAbi,
166
+ client: l1Client,
167
+ });
168
+
169
+ const gseAddress = await rollup.read.getGSE();
170
+
171
+ const gse = new GSEContract(l1Client, gseAddress);
172
+
173
+ const registrationTuple = await gse.makeRegistrationTuple(blsSecretKey);
174
+
175
+ const l1TxUtils = createL1TxUtilsFromViemWallet(l1Client, debugLogger);
176
+
177
+ const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
178
+ to: rollupAddress.toString(),
179
+ data: encodeFunctionData({
180
+ abi: RollupAbi,
181
+ functionName: 'deposit',
182
+ args: [
183
+ attesterAddress.toString(),
184
+ withdrawerAddress.toString(),
185
+ registrationTuple.publicKeyInG1,
186
+ registrationTuple.publicKeyInG2,
187
+ registrationTuple.proofOfPossession,
188
+ moveWithLatestRollup,
189
+ ],
190
+ }),
191
+ abi: StakingAssetHandlerAbi,
192
+ });
193
+ dualLog(`Transaction hash: ${receipt.transactionHash}`);
194
+ await l1Client.waitForTransactionReceipt({ hash: receipt.transactionHash });
195
+ if (isAnvilTestChain(chainId)) {
196
+ dualLog(`Funding validator on L1`);
197
+ const cheatCodes = new EthCheatCodes(rpcUrls, debugLogger);
198
+ await cheatCodes.setBalance(attesterAddress, 10n ** 20n);
199
+ } else {
200
+ const balance = await l1Client.getBalance({ address: attesterAddress.toString() });
201
+ dualLog(`Validator balance: ${formatEther(balance)} ETH`);
202
+ if (balance === 0n) {
203
+ dualLog(`WARNING: Proposer has no balance. Remember to fund it!`);
204
+ }
205
+ }
206
+ }
207
+
134
208
  export async function removeL1Validator({
135
209
  rpcUrls,
136
210
  chainId,
@@ -0,0 +1,420 @@
1
+ import { DefaultL1ContractsConfig, type L1ContractsConfig } from '@aztec/ethereum';
2
+ import type { EnvVar, NetworkNames } from '@aztec/foundation/config';
3
+ import { EthAddress } from '@aztec/foundation/eth-address';
4
+ import type { SharedNodeConfig } from '@aztec/node-lib/config';
5
+ import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
6
+
7
+ import { mkdir, readFile, stat, writeFile } from 'fs/promises';
8
+ import path, { dirname, join } from 'path';
9
+
10
+ import publicIncludeMetrics from '../../public_include_metric_prefixes.json' with { type: 'json' };
11
+
12
+ export type L2ChainConfig = L1ContractsConfig &
13
+ Omit<SlasherConfig, 'slashValidatorsNever' | 'slashValidatorsAlways'> & {
14
+ l1ChainId: number;
15
+ testAccounts: boolean;
16
+ sponsoredFPC: boolean;
17
+ p2pEnabled: boolean;
18
+ p2pBootstrapNodes: string[];
19
+ registryAddress: string;
20
+ slashFactoryAddress: string;
21
+ feeAssetHandlerAddress: string;
22
+ seqMinTxsPerBlock: number;
23
+ seqMaxTxsPerBlock: number;
24
+ realProofs: boolean;
25
+ snapshotsUrl: string;
26
+ autoUpdate: SharedNodeConfig['autoUpdate'];
27
+ autoUpdateUrl?: string;
28
+ maxTxPoolSize: number;
29
+ publicIncludeMetrics?: string[];
30
+ publicMetricsCollectorUrl?: string;
31
+ publicMetricsCollectFrom?: string[];
32
+
33
+ // Control whether sentinel is enabled or not. Needed for slashing
34
+ sentinelEnabled: boolean;
35
+ };
36
+
37
+ export const stagingIgnitionL2ChainConfig: L2ChainConfig = {
38
+ l1ChainId: 11155111,
39
+ testAccounts: true,
40
+ sponsoredFPC: false,
41
+ p2pEnabled: true,
42
+ p2pBootstrapNodes: [],
43
+ registryAddress: '0xf299347e765cfb27f913bde8e4983fd0f195676f',
44
+ slashFactoryAddress: '',
45
+ feeAssetHandlerAddress: '',
46
+ seqMinTxsPerBlock: 0,
47
+ seqMaxTxsPerBlock: 0,
48
+ realProofs: true,
49
+ snapshotsUrl: 'https://storage.googleapis.com/aztec-testnet/snapshots/staging-ignition/',
50
+ autoUpdate: 'config-and-version',
51
+ autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/staging-ignition.json',
52
+ maxTxPoolSize: 100_000_000, // 100MB
53
+ publicIncludeMetrics,
54
+ publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
55
+ publicMetricsCollectFrom: ['sequencer'],
56
+
57
+ ...DefaultL1ContractsConfig,
58
+
59
+ /** How many seconds an L1 slot lasts. */
60
+ ethereumSlotDuration: 12,
61
+ /** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */
62
+ aztecSlotDuration: 36,
63
+ /** How many L2 slots an epoch lasts. */
64
+ aztecEpochDuration: 32,
65
+ /** The target validator committee size. */
66
+ aztecTargetCommitteeSize: 48,
67
+ /** The number of epochs after an epoch ends that proofs are still accepted. */
68
+ aztecProofSubmissionEpochs: 1,
69
+ /** The mana target for the rollup */
70
+ manaTarget: 0n,
71
+ /** The proving cost per mana */
72
+ provingCostPerMana: 0n,
73
+
74
+ slasherFlavor: 'none',
75
+ slashAmountSmall: 0n,
76
+ slashAmountMedium: 0n,
77
+ slashAmountLarge: 0n,
78
+ slashMinPenaltyPercentage: 0.5,
79
+ slashMaxPenaltyPercentage: 200,
80
+ slashInactivityTargetPercentage: 0,
81
+ slashInactivityConsecutiveEpochThreshold: 1,
82
+ slashInactivityPenalty: 0n,
83
+ slashPrunePenalty: 0n,
84
+ slashDataWithholdingPenalty: 0n,
85
+ slashProposeInvalidAttestationsPenalty: 0n,
86
+ slashAttestDescendantOfInvalidPenalty: 0n,
87
+ slashBroadcastedInvalidBlockPenalty: 0n,
88
+ slashMaxPayloadSize: 50,
89
+ slashGracePeriodL2Slots: 0,
90
+ slashUnknownPenalty: 0n,
91
+ slashOffenseExpirationRounds: 10,
92
+ sentinelEnabled: false,
93
+ };
94
+
95
+ export const stagingPublicL2ChainConfig: L2ChainConfig = {
96
+ l1ChainId: 11155111,
97
+ testAccounts: false,
98
+ sponsoredFPC: true,
99
+ p2pEnabled: true,
100
+ p2pBootstrapNodes: [],
101
+ registryAddress: '0x2e48addca360da61e4d6c21ff2b1961af56eb83b',
102
+ slashFactoryAddress: '0xe19410632fd00695bc5a08dd82044b7b26317742',
103
+ feeAssetHandlerAddress: '0xb46dc3d91f849999330b6dd93473fa29fc45b076',
104
+ seqMinTxsPerBlock: 0,
105
+ seqMaxTxsPerBlock: 20,
106
+ realProofs: true,
107
+ snapshotsUrl: 'https://storage.googleapis.com/aztec-testnet/snapshots/staging-public/',
108
+ autoUpdate: 'config-and-version',
109
+ autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/staging-public.json',
110
+ publicIncludeMetrics,
111
+ publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
112
+ publicMetricsCollectFrom: ['sequencer'],
113
+ maxTxPoolSize: 100_000_000, // 100MB
114
+
115
+ // Deployment stuff
116
+ /** How many seconds an L1 slot lasts. */
117
+ ethereumSlotDuration: 12,
118
+ /** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */
119
+ aztecSlotDuration: 36,
120
+ /** How many L2 slots an epoch lasts. */
121
+ aztecEpochDuration: 32,
122
+ /** The target validator committee size. */
123
+ aztecTargetCommitteeSize: 48,
124
+ /** The number of epochs after an epoch ends that proofs are still accepted. */
125
+ aztecProofSubmissionEpochs: 1,
126
+ /** The deposit amount for a validator */
127
+ activationThreshold: DefaultL1ContractsConfig.activationThreshold,
128
+ /** The minimum stake for a validator. */
129
+ ejectionThreshold: DefaultL1ContractsConfig.ejectionThreshold,
130
+ /** The slashing round size */
131
+ slashingRoundSizeInEpochs: DefaultL1ContractsConfig.slashingRoundSizeInEpochs,
132
+ /** Governance proposing round size */
133
+ governanceProposerRoundSize: DefaultL1ContractsConfig.governanceProposerRoundSize,
134
+ /** The mana target for the rollup */
135
+ manaTarget: DefaultL1ContractsConfig.manaTarget,
136
+ /** The proving cost per mana */
137
+ provingCostPerMana: DefaultL1ContractsConfig.provingCostPerMana,
138
+ /** Exit delay for stakers */
139
+ exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
140
+ /** Tally-style slashing */
141
+ slasherFlavor: 'tally',
142
+ /** Allow one round for vetoing */
143
+ slashingExecutionDelayInRounds: 1,
144
+ /** How long for a slash payload to be executed */
145
+ slashingLifetimeInRounds: 5,
146
+ /** Allow 2 rounds to discover faults */
147
+ slashingOffsetInRounds: 2,
148
+ /** No slash vetoer */
149
+ slashingVetoer: EthAddress.ZERO,
150
+ /** Use default slash amounts */
151
+ slashAmountSmall: DefaultL1ContractsConfig.slashAmountSmall,
152
+ slashAmountMedium: DefaultL1ContractsConfig.slashAmountMedium,
153
+ slashAmountLarge: DefaultL1ContractsConfig.slashAmountLarge,
154
+
155
+ // Slashing stuff
156
+ slashMinPenaltyPercentage: 0.5,
157
+ slashMaxPenaltyPercentage: 2.0,
158
+ slashInactivityTargetPercentage: 0.7,
159
+ slashInactivityConsecutiveEpochThreshold: 1,
160
+ slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
161
+ slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
162
+ slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
163
+ slashProposeInvalidAttestationsPenalty: DefaultL1ContractsConfig.slashAmountLarge,
164
+ slashAttestDescendantOfInvalidPenalty: DefaultL1ContractsConfig.slashAmountLarge,
165
+ slashUnknownPenalty: DefaultL1ContractsConfig.slashAmountSmall,
166
+ slashBroadcastedInvalidBlockPenalty: DefaultL1ContractsConfig.slashAmountMedium,
167
+ slashMaxPayloadSize: 50,
168
+ slashGracePeriodL2Slots: 32 * 2, // Two epochs from genesis
169
+ slashOffenseExpirationRounds: 8,
170
+ sentinelEnabled: true,
171
+ };
172
+
173
+ export const testnetL2ChainConfig: L2ChainConfig = {
174
+ l1ChainId: 11155111,
175
+ testAccounts: false,
176
+ sponsoredFPC: true,
177
+ p2pEnabled: true,
178
+ p2pBootstrapNodes: [],
179
+ registryAddress: '0xcfe61b2574984326679cd15c6566fbd4a724f3b4',
180
+ slashFactoryAddress: '0x58dc5b14f9d3085c9106f5b8208a1026f94614f0',
181
+ feeAssetHandlerAddress: '0x7abdec6e68ae27c37feb6a77371382a109ec4763',
182
+ seqMinTxsPerBlock: 0,
183
+ seqMaxTxsPerBlock: 20,
184
+ realProofs: true,
185
+ snapshotsUrl: 'https://storage.googleapis.com/aztec-testnet/snapshots/testnet/',
186
+ autoUpdate: 'config-and-version',
187
+ autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/testnet.json',
188
+ maxTxPoolSize: 100_000_000, // 100MB
189
+ publicIncludeMetrics,
190
+ publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
191
+ publicMetricsCollectFrom: ['sequencer'],
192
+
193
+ // Deployment stuff
194
+ /** How many seconds an L1 slot lasts. */
195
+ ethereumSlotDuration: 12,
196
+ /** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */
197
+ aztecSlotDuration: 36,
198
+ /** How many L2 slots an epoch lasts. */
199
+ aztecEpochDuration: 32,
200
+ /** The target validator committee size. */
201
+ aztecTargetCommitteeSize: 48,
202
+ /** The number of epochs after an epoch ends that proofs are still accepted. */
203
+ aztecProofSubmissionEpochs: 1,
204
+ /** The deposit amount for a validator */
205
+ activationThreshold: DefaultL1ContractsConfig.activationThreshold,
206
+ /** The minimum stake for a validator. */
207
+ ejectionThreshold: DefaultL1ContractsConfig.ejectionThreshold,
208
+ /** The slashing round size */
209
+ slashingRoundSizeInEpochs: DefaultL1ContractsConfig.slashingRoundSizeInEpochs,
210
+ /** Governance proposing round size */
211
+ governanceProposerRoundSize: DefaultL1ContractsConfig.governanceProposerRoundSize,
212
+ /** The mana target for the rollup */
213
+ manaTarget: DefaultL1ContractsConfig.manaTarget,
214
+ /** The proving cost per mana */
215
+ provingCostPerMana: DefaultL1ContractsConfig.provingCostPerMana,
216
+ /** Exit delay for stakers */
217
+ exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
218
+ /** Tally-style slashing */
219
+ slasherFlavor: 'tally',
220
+ /** Allow one round for vetoing */
221
+ slashingExecutionDelayInRounds: 1,
222
+ /** How long for a slash payload to be executed */
223
+ slashingLifetimeInRounds: 5,
224
+ /** Allow 2 rounds to discover faults */
225
+ slashingOffsetInRounds: 2,
226
+ /** No slash vetoer */
227
+ slashingVetoer: EthAddress.ZERO,
228
+ /** Use default slash amounts */
229
+ slashAmountSmall: DefaultL1ContractsConfig.slashAmountSmall,
230
+ slashAmountMedium: DefaultL1ContractsConfig.slashAmountMedium,
231
+ slashAmountLarge: DefaultL1ContractsConfig.slashAmountLarge,
232
+
233
+ // Slashing stuff
234
+ slashMinPenaltyPercentage: 0.5,
235
+ slashMaxPenaltyPercentage: 2.0,
236
+ slashInactivityTargetPercentage: 0.7,
237
+ slashInactivityConsecutiveEpochThreshold: 1,
238
+ slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
239
+ slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
240
+ slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
241
+ slashProposeInvalidAttestationsPenalty: DefaultL1ContractsConfig.slashAmountLarge,
242
+ slashAttestDescendantOfInvalidPenalty: DefaultL1ContractsConfig.slashAmountLarge,
243
+ slashUnknownPenalty: DefaultL1ContractsConfig.slashAmountSmall,
244
+ slashBroadcastedInvalidBlockPenalty: DefaultL1ContractsConfig.slashAmountMedium,
245
+ slashMaxPayloadSize: 50,
246
+ slashGracePeriodL2Slots: 32 * 2, // Two epochs from genesis
247
+ slashOffenseExpirationRounds: 8,
248
+ sentinelEnabled: true,
249
+ };
250
+
251
+ const BOOTNODE_CACHE_DURATION_MS = 60 * 60 * 1000; // 1 hour;
252
+
253
+ export async function getBootnodes(networkName: NetworkNames, cacheDir?: string) {
254
+ const cacheFile = cacheDir ? join(cacheDir, networkName, 'bootnodes.json') : undefined;
255
+ try {
256
+ if (cacheFile) {
257
+ const info = await stat(cacheFile);
258
+ if (info.mtimeMs + BOOTNODE_CACHE_DURATION_MS > Date.now()) {
259
+ return JSON.parse(await readFile(cacheFile, 'utf-8'))['bootnodes'];
260
+ }
261
+ }
262
+ } catch {
263
+ // no-op. Get the remote-file
264
+ }
265
+
266
+ const url = `http://static.aztec.network/${networkName}/bootnodes.json`;
267
+ const response = await fetch(url);
268
+ if (!response.ok) {
269
+ throw new Error(
270
+ `Failed to fetch basic contract addresses from ${url}. Check you are using a correct network name.`,
271
+ );
272
+ }
273
+ const json = await response.json();
274
+
275
+ try {
276
+ if (cacheFile) {
277
+ await mkdir(dirname(cacheFile), { recursive: true });
278
+ await writeFile(cacheFile, JSON.stringify(json), 'utf-8');
279
+ }
280
+ } catch {
281
+ // no-op
282
+ }
283
+
284
+ return json['bootnodes'];
285
+ }
286
+
287
+ export async function getL2ChainConfig(
288
+ networkName: NetworkNames,
289
+ cacheDir?: string,
290
+ ): Promise<L2ChainConfig | undefined> {
291
+ let config: L2ChainConfig | undefined;
292
+ if (networkName === 'staging-public') {
293
+ config = { ...stagingPublicL2ChainConfig };
294
+ } else if (networkName === 'testnet') {
295
+ config = { ...testnetL2ChainConfig };
296
+ } else if (networkName === 'staging-ignition') {
297
+ config = { ...stagingIgnitionL2ChainConfig };
298
+ }
299
+ if (!config) {
300
+ return undefined;
301
+ }
302
+ // If the bootnodes are not set, get them from the network
303
+ const bootnodeKey: EnvVar = 'BOOTSTRAP_NODES';
304
+ if (!process.env[bootnodeKey]) {
305
+ config.p2pBootstrapNodes = await getBootnodes(networkName, cacheDir);
306
+ }
307
+ return config;
308
+ }
309
+
310
+ function enrichVar(envVar: EnvVar, value: string | undefined) {
311
+ // Don't override
312
+ if (process.env[envVar] || value === undefined) {
313
+ return;
314
+ }
315
+ process.env[envVar] = value;
316
+ }
317
+
318
+ function enrichEthAddressVar(envVar: EnvVar, value: string) {
319
+ // EthAddress doesn't like being given empty strings
320
+ if (value === '') {
321
+ enrichVar(envVar, EthAddress.ZERO.toString());
322
+ return;
323
+ }
324
+ enrichVar(envVar, value);
325
+ }
326
+
327
+ function getDefaultDataDir(networkName: NetworkNames): string {
328
+ return path.join(process.env.HOME || '~', '.aztec', networkName, 'data');
329
+ }
330
+
331
+ export async function enrichEnvironmentWithChainConfig(networkName: NetworkNames) {
332
+ if (networkName === 'local') {
333
+ return;
334
+ }
335
+
336
+ enrichVar('DATA_DIRECTORY', getDefaultDataDir(networkName));
337
+ const cacheDir = process.env.DATA_DIRECTORY ? join(process.env.DATA_DIRECTORY, 'cache') : undefined;
338
+ const config = await getL2ChainConfig(networkName, cacheDir);
339
+
340
+ if (!config) {
341
+ throw new Error(`Unknown network name: ${networkName}`);
342
+ }
343
+
344
+ enrichVar('BOOTSTRAP_NODES', config.p2pBootstrapNodes.join(','));
345
+ enrichVar('TEST_ACCOUNTS', config.testAccounts.toString());
346
+ enrichVar('SPONSORED_FPC', config.sponsoredFPC.toString());
347
+ enrichVar('P2P_ENABLED', config.p2pEnabled.toString());
348
+ enrichVar('L1_CHAIN_ID', config.l1ChainId.toString());
349
+ enrichVar('SEQ_MIN_TX_PER_BLOCK', config.seqMinTxsPerBlock.toString());
350
+ enrichVar('SEQ_MAX_TX_PER_BLOCK', config.seqMaxTxsPerBlock.toString());
351
+ enrichVar('PROVER_REAL_PROOFS', config.realProofs.toString());
352
+ enrichVar('PXE_PROVER_ENABLED', config.realProofs.toString());
353
+ enrichVar('SYNC_SNAPSHOTS_URL', config.snapshotsUrl);
354
+ enrichVar('P2P_MAX_TX_POOL_SIZE', config.maxTxPoolSize.toString());
355
+
356
+ if (config.autoUpdate) {
357
+ enrichVar('AUTO_UPDATE', config.autoUpdate?.toString());
358
+ }
359
+
360
+ if (config.autoUpdateUrl) {
361
+ enrichVar('AUTO_UPDATE_URL', config.autoUpdateUrl);
362
+ }
363
+
364
+ if (config.publicIncludeMetrics) {
365
+ enrichVar('PUBLIC_OTEL_INCLUDE_METRICS', config.publicIncludeMetrics.join(','));
366
+ }
367
+
368
+ if (config.publicMetricsCollectorUrl) {
369
+ enrichVar('PUBLIC_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT', config.publicMetricsCollectorUrl);
370
+ }
371
+
372
+ if (config.publicMetricsCollectFrom) {
373
+ enrichVar('PUBLIC_OTEL_COLLECT_FROM', config.publicMetricsCollectFrom.join(','));
374
+ }
375
+
376
+ enrichEthAddressVar('REGISTRY_CONTRACT_ADDRESS', config.registryAddress);
377
+ enrichEthAddressVar('SLASH_FACTORY_CONTRACT_ADDRESS', config.slashFactoryAddress);
378
+ enrichEthAddressVar('FEE_ASSET_HANDLER_CONTRACT_ADDRESS', config.feeAssetHandlerAddress);
379
+
380
+ // Deployment stuff
381
+ enrichVar('ETHEREUM_SLOT_DURATION', config.ethereumSlotDuration.toString());
382
+ enrichVar('AZTEC_SLOT_DURATION', config.aztecSlotDuration.toString());
383
+ enrichVar('AZTEC_EPOCH_DURATION', config.aztecEpochDuration.toString());
384
+ enrichVar('AZTEC_TARGET_COMMITTEE_SIZE', config.aztecTargetCommitteeSize.toString());
385
+ enrichVar('AZTEC_PROOF_SUBMISSION_EPOCHS', config.aztecProofSubmissionEpochs.toString());
386
+ enrichVar('AZTEC_ACTIVATION_THRESHOLD', config.activationThreshold.toString());
387
+ enrichVar('AZTEC_EJECTION_THRESHOLD', config.ejectionThreshold.toString());
388
+ enrichVar('AZTEC_SLASHING_QUORUM', config.slashingQuorum?.toString());
389
+ enrichVar('AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS', config.slashingRoundSizeInEpochs.toString());
390
+ enrichVar('AZTEC_GOVERNANCE_PROPOSER_QUORUM', config.governanceProposerQuorum?.toString());
391
+ enrichVar('AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE', config.governanceProposerRoundSize.toString());
392
+ enrichVar('AZTEC_MANA_TARGET', config.manaTarget.toString());
393
+ enrichVar('AZTEC_PROVING_COST_PER_MANA', config.provingCostPerMana.toString());
394
+ enrichVar('AZTEC_SLASH_AMOUNT_SMALL', config.slashAmountSmall.toString());
395
+ enrichVar('AZTEC_SLASH_AMOUNT_MEDIUM', config.slashAmountMedium.toString());
396
+ enrichVar('AZTEC_SLASH_AMOUNT_LARGE', config.slashAmountLarge.toString());
397
+ enrichVar('AZTEC_SLASHING_LIFETIME_IN_ROUNDS', config.slashingLifetimeInRounds.toString());
398
+ enrichVar('AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS', config.slashingExecutionDelayInRounds.toString());
399
+ enrichVar('AZTEC_SLASHING_OFFSET_IN_ROUNDS', config.slashingOffsetInRounds.toString());
400
+ enrichVar('AZTEC_SLASHER_FLAVOR', config.slasherFlavor);
401
+ enrichVar('AZTEC_EXIT_DELAY_SECONDS', config.exitDelaySeconds.toString());
402
+ enrichEthAddressVar('AZTEC_SLASHING_VETOER', config.slashingVetoer.toString());
403
+
404
+ // Slashing
405
+ enrichVar('SLASH_MIN_PENALTY_PERCENTAGE', config.slashMinPenaltyPercentage.toString());
406
+ enrichVar('SLASH_MAX_PENALTY_PERCENTAGE', config.slashMaxPenaltyPercentage.toString());
407
+ enrichVar('SLASH_PRUNE_PENALTY', config.slashPrunePenalty.toString());
408
+ enrichVar('SLASH_DATA_WITHHOLDING_PENALTY', config.slashDataWithholdingPenalty.toString());
409
+ enrichVar('SLASH_INACTIVITY_TARGET_PERCENTAGE', config.slashInactivityTargetPercentage.toString());
410
+ enrichVar('SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD', config.slashInactivityConsecutiveEpochThreshold.toString());
411
+ enrichVar('SLASH_INACTIVITY_PENALTY', config.slashInactivityPenalty.toString());
412
+ enrichVar('SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY', config.slashProposeInvalidAttestationsPenalty.toString());
413
+ enrichVar('SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY', config.slashAttestDescendantOfInvalidPenalty.toString());
414
+ enrichVar('SLASH_UNKNOWN_PENALTY', config.slashUnknownPenalty.toString());
415
+ enrichVar('SLASH_INVALID_BLOCK_PENALTY', config.slashBroadcastedInvalidBlockPenalty.toString());
416
+ enrichVar('SLASH_OFFENSE_EXPIRATION_ROUNDS', config.slashOffenseExpirationRounds.toString());
417
+ enrichVar('SLASH_MAX_PAYLOAD_SIZE', config.slashMaxPayloadSize.toString());
418
+
419
+ enrichVar('SENTINEL_ENABLED', config.sentinelEnabled.toString());
420
+ }
@@ -0,0 +1,28 @@
1
+ import { type L1ContractAddresses, RegistryContract, getL1ContractsConfig, getPublicClient } from '@aztec/ethereum';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+
4
+ export async function getL1Config(
5
+ registryAddress: EthAddress,
6
+ l1RpcUrls: string[],
7
+ l1ChainId: number,
8
+ rollupVersion: number | 'canonical' = 'canonical',
9
+ ): Promise<{ addresses: L1ContractAddresses; config: Awaited<ReturnType<typeof getL1ContractsConfig>> }> {
10
+ const publicClient = getPublicClient({ l1RpcUrls, l1ChainId });
11
+ const addresses = await RegistryContract.collectAddresses(publicClient, registryAddress, rollupVersion);
12
+
13
+ const config = await getL1ContractsConfig(publicClient, addresses);
14
+
15
+ return {
16
+ addresses,
17
+ config,
18
+ };
19
+ }
20
+
21
+ export async function getL1RollupAddressFromEnv(l1RpcUrls: string[], l1ChainId: number) {
22
+ const registryAddress = process.env.REGISTRY_CONTRACT_ADDRESS;
23
+ if (!registryAddress || !EthAddress.isAddress(registryAddress)) {
24
+ throw new Error(`Failed to extract registry address`);
25
+ }
26
+ const { addresses } = await getL1Config(EthAddress.fromString(registryAddress), l1RpcUrls, l1ChainId);
27
+ return addresses.rollupAddress;
28
+ }
@@ -0,0 +1,2 @@
1
+ export * from './chain_l2_config.js';
2
+ export * from './get_l1_config.js';