@aztec/ethereum 0.0.1-commit.03f7ef2 → 0.0.1-commit.08c5969dc

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.
Files changed (111) hide show
  1. package/dest/config.d.ts +17 -27
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +51 -54
  4. package/dest/contracts/empire_slashing_proposer.d.ts +1 -1
  5. package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
  6. package/dest/contracts/empire_slashing_proposer.js +13 -15
  7. package/dest/contracts/fee_asset_handler.d.ts +6 -5
  8. package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
  9. package/dest/contracts/fee_asset_handler.js +11 -9
  10. package/dest/contracts/governance.d.ts +3 -1
  11. package/dest/contracts/governance.d.ts.map +1 -1
  12. package/dest/contracts/governance.js +11 -1
  13. package/dest/contracts/governance_proposer.d.ts +1 -1
  14. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  15. package/dest/contracts/governance_proposer.js +386 -9
  16. package/dest/contracts/inbox.d.ts +22 -1
  17. package/dest/contracts/inbox.d.ts.map +1 -1
  18. package/dest/contracts/inbox.js +36 -1
  19. package/dest/contracts/index.d.ts +3 -1
  20. package/dest/contracts/index.d.ts.map +1 -1
  21. package/dest/contracts/index.js +2 -0
  22. package/dest/contracts/log.d.ts +13 -0
  23. package/dest/contracts/log.d.ts.map +1 -0
  24. package/dest/contracts/log.js +1 -0
  25. package/dest/contracts/multicall.d.ts +1 -1
  26. package/dest/contracts/multicall.d.ts.map +1 -1
  27. package/dest/contracts/multicall.js +2 -1
  28. package/dest/contracts/outbox.d.ts +41 -0
  29. package/dest/contracts/outbox.d.ts.map +1 -0
  30. package/dest/contracts/outbox.js +86 -0
  31. package/dest/contracts/rollup.d.ts +161 -96
  32. package/dest/contracts/rollup.d.ts.map +1 -1
  33. package/dest/contracts/rollup.js +677 -132
  34. package/dest/contracts/tally_slashing_proposer.d.ts +1 -1
  35. package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -1
  36. package/dest/contracts/tally_slashing_proposer.js +8 -1
  37. package/dest/deploy_aztec_l1_contracts.d.ts +17 -2
  38. package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
  39. package/dest/deploy_aztec_l1_contracts.js +111 -33
  40. package/dest/generated/l1-contracts-defaults.d.ts +30 -0
  41. package/dest/generated/l1-contracts-defaults.d.ts.map +1 -0
  42. package/dest/generated/l1-contracts-defaults.js +30 -0
  43. package/dest/l1_artifacts.d.ts +4904 -1533
  44. package/dest/l1_artifacts.d.ts.map +1 -1
  45. package/dest/l1_tx_utils/constants.d.ts +1 -1
  46. package/dest/l1_tx_utils/constants.js +2 -2
  47. package/dest/l1_tx_utils/fee-strategies/index.d.ts +3 -2
  48. package/dest/l1_tx_utils/fee-strategies/index.d.ts.map +1 -1
  49. package/dest/l1_tx_utils/fee-strategies/index.js +2 -1
  50. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts +2 -12
  51. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts.map +1 -1
  52. package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +36 -18
  53. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts +2 -11
  54. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts.map +1 -1
  55. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +37 -19
  56. package/dest/l1_tx_utils/fee-strategies/types.d.ts +14 -27
  57. package/dest/l1_tx_utils/fee-strategies/types.d.ts.map +1 -1
  58. package/dest/l1_tx_utils/fee-strategies/types.js +0 -21
  59. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +2 -2
  60. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -1
  61. package/dest/l1_tx_utils/l1_fee_analyzer.js +3 -3
  62. package/dest/l1_tx_utils/l1_tx_utils.js +6 -6
  63. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +1 -5
  64. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
  65. package/dest/l1_tx_utils/readonly_l1_tx_utils.js +17 -54
  66. package/dest/publisher_manager.d.ts +3 -2
  67. package/dest/publisher_manager.d.ts.map +1 -1
  68. package/dest/publisher_manager.js +2 -2
  69. package/dest/queries.d.ts +2 -2
  70. package/dest/queries.d.ts.map +1 -1
  71. package/dest/queries.js +12 -4
  72. package/dest/test/chain_monitor.js +1 -2
  73. package/dest/test/eth_cheat_codes.d.ts +13 -1
  74. package/dest/test/eth_cheat_codes.d.ts.map +1 -1
  75. package/dest/test/rollup_cheat_codes.d.ts +5 -2
  76. package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
  77. package/dest/test/rollup_cheat_codes.js +19 -2
  78. package/dest/test/start_anvil.js +1 -1
  79. package/dest/utils.d.ts +2 -1
  80. package/dest/utils.d.ts.map +1 -1
  81. package/dest/utils.js +46 -0
  82. package/package.json +8 -7
  83. package/src/config.ts +62 -53
  84. package/src/contracts/README.md +157 -0
  85. package/src/contracts/empire_slashing_proposer.ts +16 -27
  86. package/src/contracts/fee_asset_handler.ts +10 -7
  87. package/src/contracts/governance.ts +10 -1
  88. package/src/contracts/governance_proposer.ts +4 -1
  89. package/src/contracts/inbox.ts +53 -1
  90. package/src/contracts/index.ts +2 -0
  91. package/src/contracts/log.ts +13 -0
  92. package/src/contracts/multicall.ts +5 -2
  93. package/src/contracts/outbox.ts +98 -0
  94. package/src/contracts/rollup.ts +348 -100
  95. package/src/contracts/tally_slashing_proposer.ts +5 -1
  96. package/src/deploy_aztec_l1_contracts.ts +117 -40
  97. package/src/generated/l1-contracts-defaults.ts +32 -0
  98. package/src/l1_tx_utils/constants.ts +2 -2
  99. package/src/l1_tx_utils/fee-strategies/index.ts +1 -1
  100. package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +46 -42
  101. package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +49 -45
  102. package/src/l1_tx_utils/fee-strategies/types.ts +14 -46
  103. package/src/l1_tx_utils/l1_fee_analyzer.ts +2 -3
  104. package/src/l1_tx_utils/l1_tx_utils.ts +6 -6
  105. package/src/l1_tx_utils/readonly_l1_tx_utils.ts +23 -62
  106. package/src/publisher_manager.ts +4 -2
  107. package/src/queries.ts +11 -3
  108. package/src/test/chain_monitor.ts +1 -1
  109. package/src/test/rollup_cheat_codes.ts +21 -3
  110. package/src/test/start_anvil.ts +1 -1
  111. package/src/utils.ts +53 -0
@@ -1,11 +1,12 @@
1
1
  import type { L1TxRequest } from '@aztec/ethereum/l1-tx-utils';
2
2
  import type { ViemClient } from '@aztec/ethereum/types';
3
- import { tryExtractEvent } from '@aztec/ethereum/utils';
3
+ import { mergeAbis, tryExtractEvent } from '@aztec/ethereum/utils';
4
4
  import { SlotNumber } from '@aztec/foundation/branded-types';
5
5
  import { Buffer32 } from '@aztec/foundation/buffer';
6
6
  import { EthAddress } from '@aztec/foundation/eth-address';
7
7
  import { Signature } from '@aztec/foundation/eth-signature';
8
8
  import { hexToBuffer } from '@aztec/foundation/string';
9
+ import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
9
10
  import { TallySlashingProposerAbi } from '@aztec/l1-artifacts/TallySlashingProposerAbi';
10
11
 
11
12
  import {
@@ -160,6 +161,7 @@ export class TallySlashingProposerContract {
160
161
 
161
162
  return {
162
163
  to: this.contract.address,
164
+ abi: TallySlashingProposerAbi,
163
165
  data: encodeFunctionData({
164
166
  abi: TallySlashingProposerAbi,
165
167
  functionName: 'vote',
@@ -207,6 +209,7 @@ export class TallySlashingProposerContract {
207
209
  public buildVoteRequestWithSignature(votes: Hex, signature: { v: number; r: Hex; s: Hex }): L1TxRequest {
208
210
  return {
209
211
  to: this.contract.address,
212
+ abi: TallySlashingProposerAbi,
210
213
  data: encodeFunctionData({
211
214
  abi: TallySlashingProposerAbi,
212
215
  functionName: 'vote',
@@ -224,6 +227,7 @@ export class TallySlashingProposerContract {
224
227
  public buildExecuteRoundRequest(round: bigint, committees: EthAddress[][]): L1TxRequest {
225
228
  return {
226
229
  to: this.contract.address,
230
+ abi: mergeAbis([TallySlashingProposerAbi, SlasherAbi]),
227
231
  data: encodeFunctionData({
228
232
  abi: TallySlashingProposerAbi,
229
233
  functionName: 'executeRound',
@@ -10,10 +10,12 @@ import { fileURLToPath } from '@aztec/foundation/url';
10
10
  import { bn254 } from '@noble/curves/bn254';
11
11
  import type { Abi, Narrow } from 'abitype';
12
12
  import { spawn } from 'child_process';
13
- import { dirname, resolve } from 'path';
13
+ import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs';
14
+ import { tmpdir } from 'os';
15
+ import { dirname, join, resolve } from 'path';
14
16
  import readline from 'readline';
15
17
  import type { Hex } from 'viem';
16
- import { foundry, mainnet, sepolia } from 'viem/chains';
18
+ import { mainnet, sepolia } from 'viem/chains';
17
19
 
18
20
  import { createEthereumChain, isAnvilTestChain } from './chain.js';
19
21
  import { createExtendedL1Client } from './client.js';
@@ -29,9 +31,9 @@ const logger = createLogger('ethereum:deploy_aztec_l1_contracts');
29
31
  const JSON_DEPLOY_RESULT_PREFIX = 'JSON DEPLOY RESULT:';
30
32
 
31
33
  /**
32
- * Runs a process with the given command, arguments, and environment.
33
- * If the process outputs a line starting with JSON_DEPLOY_RESULT_PREFIX,
34
- * the JSON is parsed and returned.
34
+ * Runs a process and parses JSON deploy results from stdout.
35
+ * Lines starting with JSON_DEPLOY_RESULT_PREFIX are parsed and returned.
36
+ * All other stdout goes to logger.info, stderr goes to logger.warn.
35
37
  */
36
38
  function runProcess<T>(
37
39
  command: string,
@@ -47,26 +49,41 @@ function runProcess<T>(
47
49
  });
48
50
 
49
51
  let result: T | undefined;
52
+ let parseError: Error | undefined;
53
+ let settled = false;
50
54
 
51
55
  readline.createInterface({ input: proc.stdout }).on('line', line => {
52
56
  const trimmedLine = line.trim();
53
57
  if (trimmedLine.startsWith(JSON_DEPLOY_RESULT_PREFIX)) {
54
58
  const jsonStr = trimmedLine.slice(JSON_DEPLOY_RESULT_PREFIX.length).trim();
55
- // TODO(AD): should this be a zod parse?
56
- result = JSON.parse(jsonStr);
59
+ try {
60
+ result = JSON.parse(jsonStr);
61
+ } catch {
62
+ parseError = new Error(`Failed to parse deploy result JSON: ${jsonStr.slice(0, 200)}`);
63
+ }
57
64
  } else {
58
65
  logger.info(line);
59
66
  }
60
67
  });
61
- readline.createInterface({ input: proc.stderr }).on('line', logger.error.bind(logger));
68
+ readline.createInterface({ input: proc.stderr }).on('line', logger.warn.bind(logger));
62
69
 
63
70
  proc.on('error', error => {
71
+ if (settled) {
72
+ return;
73
+ }
74
+ settled = true;
64
75
  reject(new Error(`Failed to spawn ${command}: ${error.message}`));
65
76
  });
66
77
 
67
78
  proc.on('close', code => {
79
+ if (settled) {
80
+ return;
81
+ }
82
+ settled = true;
68
83
  if (code !== 0) {
69
- reject(new Error(`${command} exited with code ${code}. See logs for details.\n`));
84
+ reject(new Error(`${command} exited with code ${code}`));
85
+ } else if (parseError) {
86
+ reject(parseError);
70
87
  } else {
71
88
  resolve(result);
72
89
  }
@@ -107,17 +124,80 @@ export interface ValidatorJson {
107
124
  }
108
125
 
109
126
  /**
110
- * Gets the path to the l1-contracts directory.
127
+ * Gets the path to the l1-contracts foundry artifacts directory.
128
+ * These are copied from l1-contracts to yarn-project/l1-artifacts/l1-contracts
129
+ * during build to make yarn-project self-contained.
111
130
  */
112
131
  export function getL1ContractsPath(): string {
113
- // Try to find l1-contracts relative to this file
114
132
  const currentDir = dirname(fileURLToPath(import.meta.url));
115
-
116
- // Go up from yarn-project/ethereum/src to yarn-project, then to repo root, then to l1-contracts
117
- const l1ContractsPath = resolve(currentDir, '..', '..', '..', 'l1-contracts');
133
+ // Go up from yarn-project/ethereum/dest to yarn-project, then to l1-artifacts/l1-contracts
134
+ const l1ContractsPath = resolve(currentDir, '..', '..', 'l1-artifacts', 'l1-contracts');
118
135
  return l1ContractsPath;
119
136
  }
120
137
 
138
+ // Cached deployment directory
139
+ let preparedDeployDir: string | undefined;
140
+
141
+ function cleanupDeployDir() {
142
+ if (preparedDeployDir) {
143
+ try {
144
+ rmSync(preparedDeployDir, { recursive: true, force: true });
145
+ } catch {
146
+ // ignore cleanup errors
147
+ }
148
+ preparedDeployDir = undefined;
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Prepares a temp directory for forge deployment.
154
+ * Copies all artifacts with preserved timestamps (required for forge cache validity).
155
+ * A fresh broadcast/ directory is created for deployment outputs.
156
+ */
157
+ export function prepareL1ContractsForDeployment(): string {
158
+ if (preparedDeployDir && existsSync(preparedDeployDir)) {
159
+ logger.verbose(`Using cached deployment directory: ${preparedDeployDir}`);
160
+ return preparedDeployDir;
161
+ }
162
+
163
+ const basePath = getL1ContractsPath();
164
+ logger.verbose(`Preparing L1 contracts from: ${basePath}`);
165
+ const tempDir = mkdtempSync(join(tmpdir(), '.foundry-deploy-'));
166
+ logger.verbose(`Created temp directory for deployment: ${tempDir}`);
167
+ preparedDeployDir = tempDir;
168
+ process.on('exit', cleanupDeployDir);
169
+
170
+ // Copy all dirs with preserved timestamps (required for forge cache validity)
171
+ const copyOpts = { recursive: true, preserveTimestamps: true };
172
+ cpSync(join(basePath, 'out'), join(tempDir, 'out'), copyOpts);
173
+ cpSync(join(basePath, 'lib'), join(tempDir, 'lib'), copyOpts);
174
+ cpSync(join(basePath, 'cache'), join(tempDir, 'cache'), copyOpts);
175
+ cpSync(join(basePath, 'src'), join(tempDir, 'src'), copyOpts);
176
+ cpSync(join(basePath, 'script'), join(tempDir, 'script'), copyOpts);
177
+ cpSync(join(basePath, 'generated'), join(tempDir, 'generated'), copyOpts);
178
+ // Kludge: copy test/ to appease forge cache which references test/shouting.t.sol
179
+ cpSync(join(basePath, 'test'), join(tempDir, 'test'), copyOpts);
180
+ cpSync(join(basePath, 'foundry.lock'), join(tempDir, 'foundry.lock'));
181
+
182
+ // Update foundry.toml to use absolute path to solc binary (avoids copying to noexec tmpfs)
183
+ const foundryTomlPath = join(basePath, 'foundry.toml');
184
+ let foundryToml = readFileSync(foundryTomlPath, 'utf-8');
185
+ const solcPathMatch = foundryToml.match(/solc\s*=\s*"\.\/solc-([^"]+)"/);
186
+ // Did we find a hardcoded solc path that we need to make absolute?
187
+ // This code path happens in CI currently as we bundle solc there to avoid race conditions when
188
+ // downloading solc.
189
+ if (solcPathMatch) {
190
+ const solcVersion = solcPathMatch[1];
191
+ const absoluteSolcPath = join(basePath, `solc-${solcVersion}`);
192
+ foundryToml = foundryToml.replace(/solc\s*=\s*"\.\/solc-[^"]+"/, `solc = "${absoluteSolcPath}"`);
193
+ logger.verbose(`Updated solc path in foundry.toml to: ${absoluteSolcPath}`);
194
+ }
195
+ writeFileSync(join(tempDir, 'foundry.toml'), foundryToml);
196
+
197
+ mkdirSync(join(tempDir, 'broadcast'));
198
+ return tempDir;
199
+ }
200
+
121
201
  /**
122
202
  * Computes the validator data for passing to Solidity.
123
203
  * Only computes the G2 public key (which requires scalar multiplication on G2, not available in EVM).
@@ -211,7 +291,6 @@ export async function deployAztecL1Contracts(
211
291
  'Initial validator funding requires minting tokens, which is not possible with an external token.',
212
292
  );
213
293
  }
214
- const currentDir = dirname(fileURLToPath(import.meta.url));
215
294
  const chain = createEthereumChain([rpcUrl], chainId);
216
295
 
217
296
  const l1Client = createExtendedL1Client([rpcUrl], privateKey, chain.chainInfo);
@@ -240,8 +319,8 @@ export async function deployAztecL1Contracts(
240
319
  }
241
320
  }
242
321
 
243
- // Relative location of l1-contracts in monorepo or docker image.
244
- const l1ContractsPath = resolve(currentDir, '..', '..', '..', 'l1-contracts');
322
+ // Use foundry-artifacts from l1-artifacts package
323
+ const l1ContractsPath = prepareL1ContractsForDeployment();
245
324
 
246
325
  const FORGE_SCRIPT = 'script/deploy/DeployAztecL1Contracts.s.sol';
247
326
  await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
@@ -257,11 +336,8 @@ export async function deployAztecL1Contracts(
257
336
  );
258
337
  }
259
338
 
260
- // From heuristic testing. More caused issues with anvil.
261
- const MAGIC_ANVIL_BATCH_SIZE = 12;
262
- // Anvil seems to stall with unbounded batch size. Otherwise no max batch size is desirable.
339
+ const scriptPath = join(getL1ContractsPath(), 'scripts', 'forge_broadcast.js');
263
340
  const forgeArgs = [
264
- 'script',
265
341
  FORGE_SCRIPT,
266
342
  '--sig',
267
343
  'run()',
@@ -269,8 +345,6 @@ export async function deployAztecL1Contracts(
269
345
  privateKey,
270
346
  '--rpc-url',
271
347
  rpcUrl,
272
- '--broadcast',
273
- ...(chainId === foundry.id ? ['--batch-size', MAGIC_ANVIL_BATCH_SIZE.toString()] : []),
274
348
  ...(shouldVerify ? ['--verify'] : []),
275
349
  ];
276
350
  const forgeEnv = {
@@ -279,7 +353,12 @@ export async function deployAztecL1Contracts(
279
353
  FOUNDRY_PROFILE: chainId === mainnet.id ? 'production' : undefined,
280
354
  ...getDeployAztecL1ContractsEnvVars(args),
281
355
  };
282
- const result = await runProcess<ForgeL1ContractsDeployResult>('forge', forgeArgs, forgeEnv, l1ContractsPath);
356
+ const result = await runProcess<ForgeL1ContractsDeployResult>(
357
+ process.execPath,
358
+ [scriptPath, ...forgeArgs],
359
+ forgeEnv,
360
+ l1ContractsPath,
361
+ );
283
362
  if (!result) {
284
363
  throw new Error('Forge script did not output deployment result');
285
364
  }
@@ -447,6 +526,7 @@ export function getDeployAztecL1ContractsEnvVars(args: DeployAztecL1ContractsArg
447
526
  AZTEC_EJECTION_THRESHOLD: args.ejectionThreshold?.toString(),
448
527
  AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE: args.governanceProposerRoundSize?.toString(),
449
528
  AZTEC_GOVERNANCE_PROPOSER_QUORUM: args.governanceProposerQuorum?.toString(),
529
+ AZTEC_GOVERNANCE_VOTING_DURATION: args.governanceVotingDuration?.toString(),
450
530
  ZKPASSPORT_DOMAIN: args.zkPassportArgs?.zkPassportDomain,
451
531
  ZKPASSPORT_SCOPE: args.zkPassportArgs?.zkPassportScope,
452
532
  } as const;
@@ -477,14 +557,17 @@ export function getDeployRollupForUpgradeEnvVars(
477
557
  AZTEC_TARGET_COMMITTEE_SIZE: args.aztecTargetCommitteeSize.toString(),
478
558
  AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET: args.lagInEpochsForValidatorSet.toString(),
479
559
  AZTEC_LAG_IN_EPOCHS_FOR_RANDAO: args.lagInEpochsForRandao.toString(),
560
+ AZTEC_INBOX_LAG: args.inboxLag?.toString(),
480
561
  AZTEC_PROOF_SUBMISSION_EPOCHS: args.aztecProofSubmissionEpochs.toString(),
481
562
  AZTEC_LOCAL_EJECTION_THRESHOLD: args.localEjectionThreshold.toString(),
482
563
  AZTEC_SLASHING_LIFETIME_IN_ROUNDS: args.slashingLifetimeInRounds.toString(),
564
+ AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS: args.slashingExecutionDelayInRounds.toString(),
483
565
  AZTEC_SLASHING_VETOER: args.slashingVetoer.toString(),
484
566
  AZTEC_SLASHING_DISABLE_DURATION: args.slashingDisableDuration.toString(),
485
567
  AZTEC_MANA_TARGET: args.manaTarget.toString(),
486
568
  AZTEC_EXIT_DELAY_SECONDS: args.exitDelaySeconds.toString(),
487
569
  AZTEC_PROVING_COST_PER_MANA: args.provingCostPerMana.toString(),
570
+ AZTEC_INITIAL_ETH_PER_FEE_ASSET: args.initialEthPerFeeAsset.toString(),
488
571
  AZTEC_SLASHER_FLAVOR: args.slasherFlavor,
489
572
  AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS: args.slashingRoundSizeInEpochs.toString(),
490
573
  AZTEC_SLASHING_QUORUM: args.slashingQuorum?.toString(),
@@ -512,25 +595,14 @@ export const deployRollupForUpgrade = async (
512
595
  | 'zkPassportArgs'
513
596
  >,
514
597
  ) => {
515
- const currentDir = dirname(fileURLToPath(import.meta.url));
516
-
517
- // Relative location of l1-contracts in monorepo or docker image.
518
- const l1ContractsPath = resolve(currentDir, '..', '..', '..', 'l1-contracts');
598
+ // Use foundry-artifacts from l1-artifacts package
599
+ const l1ContractsPath = prepareL1ContractsForDeployment();
519
600
 
520
601
  const FORGE_SCRIPT = 'script/deploy/DeployRollupForUpgrade.s.sol';
521
602
  await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
522
603
 
523
- const forgeArgs = [
524
- 'script',
525
- FORGE_SCRIPT,
526
- '--sig',
527
- 'run()',
528
- '--private-key',
529
- privateKey,
530
- '--rpc-url',
531
- rpcUrl,
532
- '--broadcast',
533
- ];
604
+ const scriptPath = join(getL1ContractsPath(), 'scripts', 'forge_broadcast.js');
605
+ const forgeArgs = [FORGE_SCRIPT, '--sig', 'run()', '--private-key', privateKey, '--rpc-url', rpcUrl];
534
606
  const forgeEnv = {
535
607
  FOUNDRY_PROFILE: chainId === mainnet.id ? 'production' : undefined,
536
608
  // Env vars required by l1-contracts/script/deploy/RollupConfiguration.sol.
@@ -539,7 +611,12 @@ export const deployRollupForUpgrade = async (
539
611
  ...getDeployRollupForUpgradeEnvVars(args),
540
612
  };
541
613
 
542
- const result = await runProcess<ForgeRollupUpgradeResult>('forge', forgeArgs, forgeEnv, l1ContractsPath);
614
+ const result = await runProcess<ForgeRollupUpgradeResult>(
615
+ process.execPath,
616
+ [scriptPath, ...forgeArgs],
617
+ forgeEnv,
618
+ l1ContractsPath,
619
+ );
543
620
  if (!result) {
544
621
  throw new Error('Forge script did not output deployment result');
545
622
  }
@@ -0,0 +1,32 @@
1
+ // Auto-generated from spartan/environments/network-defaults.yml
2
+ // Do not edit manually - run yarn generate to regenerate
3
+
4
+ /** Default L1 contracts configuration values from network-defaults.yml */
5
+ export const l1ContractsDefaultEnv = {
6
+ ETHEREUM_SLOT_DURATION: 12,
7
+ AZTEC_SLOT_DURATION: 36,
8
+ AZTEC_EPOCH_DURATION: 32,
9
+ AZTEC_TARGET_COMMITTEE_SIZE: 48,
10
+ AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET: 2,
11
+ AZTEC_LAG_IN_EPOCHS_FOR_RANDAO: 2,
12
+ AZTEC_ACTIVATION_THRESHOLD: 100000000000000000000,
13
+ AZTEC_EJECTION_THRESHOLD: 50000000000000000000,
14
+ AZTEC_LOCAL_EJECTION_THRESHOLD: 98000000000000000000,
15
+ AZTEC_EXIT_DELAY_SECONDS: 172800,
16
+ AZTEC_INBOX_LAG: 1,
17
+ AZTEC_PROOF_SUBMISSION_EPOCHS: 1,
18
+ AZTEC_MANA_TARGET: 100000000,
19
+ AZTEC_PROVING_COST_PER_MANA: 100,
20
+ AZTEC_INITIAL_ETH_PER_FEE_ASSET: 10000000,
21
+ AZTEC_SLASHER_FLAVOR: 'tally',
22
+ AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS: 4,
23
+ AZTEC_SLASHING_LIFETIME_IN_ROUNDS: 5,
24
+ AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS: 0,
25
+ AZTEC_SLASHING_OFFSET_IN_ROUNDS: 2,
26
+ AZTEC_SLASHING_VETOER: '0x0000000000000000000000000000000000000000',
27
+ AZTEC_SLASHING_DISABLE_DURATION: 432000,
28
+ AZTEC_SLASH_AMOUNT_SMALL: 10000000000000000000,
29
+ AZTEC_SLASH_AMOUNT_MEDIUM: 20000000000000000000,
30
+ AZTEC_SLASH_AMOUNT_LARGE: 50000000000000000000,
31
+ AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE: 300,
32
+ } as const;
@@ -3,8 +3,8 @@
3
3
  // 1_000_000_000_000_000_000 Wei = 1 ETH
4
4
  export const WEI_CONST = 1_000_000_000n;
5
5
 
6
- // @note using this large gas limit to avoid the issue of `gas limit too low` when estimating gas in reth
7
- export const LARGE_GAS_LIMIT = 12_000_000n;
6
+ // EIP-7825: protocol-level cap on tx gas limit (2^24). Clients reject above this.
7
+ export const MAX_L1_TX_LIMIT = 16_777_216n;
8
8
 
9
9
  // setting a minimum bump percentage to 10% due to geth's implementation
10
10
  // https://github.com/ethereum/go-ethereum/blob/e3d61e6db028c412f74bc4d4c7e117a9e29d0de0/core/txpool/legacypool/list.go#L298
@@ -4,13 +4,13 @@ import type { PriorityFeeStrategy } from './types.js';
4
4
 
5
5
  export {
6
6
  HISTORICAL_BLOCK_COUNT,
7
- executeStrategy,
8
7
  type PriorityFeeStrategy,
9
8
  type PriorityFeeStrategyContext,
10
9
  type PriorityFeeStrategyResult,
11
10
  } from './types.js';
12
11
 
13
12
  export { P75AllTxsPriorityFeeStrategy } from './p75_competitive.js';
13
+ export { P75BlobTxsOnlyPriorityFeeStrategy } from './p75_competitive_blob_txs_only.js';
14
14
 
15
15
  /**
16
16
  * Default list of priority fee strategies to analyze.
@@ -12,50 +12,54 @@ import {
12
12
  type PriorityFeeStrategyResult,
13
13
  } from './types.js';
14
14
 
15
- /**
16
- * Type for the promises required by the competitive strategy
17
- */
18
- type P75AllTxsStrategyPromises = {
19
- networkEstimate: Promise<bigint>;
20
- pendingBlock: Promise<Awaited<ReturnType<ViemClient['getBlock']>> | null>;
21
- feeHistory: Promise<Awaited<ReturnType<ViemClient['getFeeHistory']>> | null>;
22
- };
23
-
24
15
  /**
25
16
  * Our current competitive priority fee strategy.
26
17
  * Analyzes p75 of pending transactions and 5-block fee history to determine a competitive priority fee.
27
18
  * Falls back to network estimate if data is unavailable.
28
19
  */
29
- export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStrategyPromises> = {
20
+ export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy = {
30
21
  name: 'Competitive (P75 + History) - CURRENT',
31
22
  id: 'p75_pending_txs_and_history_all_txs',
32
23
 
33
- getRequiredPromises(client: ViemClient): P75AllTxsStrategyPromises {
34
- return {
35
- networkEstimate: client.estimateMaxPriorityFeePerGas().catch(() => 0n),
36
- pendingBlock: client.getBlock({ blockTag: 'pending', includeTransactions: true }).catch(() => null),
37
- feeHistory: client
38
- .getFeeHistory({
39
- blockCount: HISTORICAL_BLOCK_COUNT,
40
- rewardPercentiles: [75],
41
- blockTag: 'latest',
42
- })
43
- .catch(() => null),
44
- };
45
- },
46
-
47
- calculate(
48
- results: {
49
- [K in keyof P75AllTxsStrategyPromises]: PromiseSettledResult<Awaited<P75AllTxsStrategyPromises[K]>>;
50
- },
51
- context: PriorityFeeStrategyContext,
52
- ): PriorityFeeStrategyResult {
53
- const { logger } = context;
24
+ async execute(client: ViemClient, context: PriorityFeeStrategyContext): Promise<PriorityFeeStrategyResult> {
25
+ const { isBlobTx, logger } = context;
26
+
27
+ // Fire all RPC calls in parallel
28
+ const [latestBlockResult, blobBaseFeeResult, networkEstimateResult, pendingBlockResult, feeHistoryResult] =
29
+ await Promise.allSettled([
30
+ client.getBlock({ blockTag: 'latest' }),
31
+ isBlobTx ? client.getBlobBaseFee() : Promise.resolve(undefined),
32
+ client.estimateMaxPriorityFeePerGas().catch(() => 0n),
33
+ client.getBlock({ blockTag: 'pending', includeTransactions: true }).catch(() => null),
34
+ client
35
+ .getFeeHistory({
36
+ blockCount: HISTORICAL_BLOCK_COUNT,
37
+ rewardPercentiles: [75],
38
+ blockTag: 'latest',
39
+ })
40
+ .catch(() => null),
41
+ ]);
42
+
43
+ // Extract latest block
44
+ if (latestBlockResult.status === 'rejected') {
45
+ throw new Error(`Failed to get latest block: ${latestBlockResult.reason}`);
46
+ }
47
+ const latestBlock = latestBlockResult.value;
48
+
49
+ // Extract blob base fee (only for blob txs)
50
+ let blobBaseFee: bigint | undefined;
51
+ if (isBlobTx) {
52
+ if (blobBaseFeeResult.status === 'fulfilled' && typeof blobBaseFeeResult.value === 'bigint') {
53
+ blobBaseFee = blobBaseFeeResult.value;
54
+ } else {
55
+ logger?.warn('Failed to get L1 blob base fee');
56
+ }
57
+ }
54
58
 
55
- // Extract network estimate from settled result
59
+ // Extract network estimate
56
60
  const networkEstimate =
57
- results.networkEstimate.status === 'fulfilled' && typeof results.networkEstimate.value === 'bigint'
58
- ? results.networkEstimate.value
61
+ networkEstimateResult.status === 'fulfilled' && typeof networkEstimateResult.value === 'bigint'
62
+ ? networkEstimateResult.value
59
63
  : 0n;
60
64
 
61
65
  let competitiveFee = networkEstimate;
@@ -63,8 +67,8 @@ export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStrategy
63
67
  networkEstimateGwei: formatGwei(networkEstimate),
64
68
  };
65
69
 
66
- // Extract pending block from settled result
67
- const pendingBlock = results.pendingBlock.status === 'fulfilled' ? results.pendingBlock.value : null;
70
+ // Extract pending block
71
+ const pendingBlock = pendingBlockResult.status === 'fulfilled' ? pendingBlockResult.value : null;
68
72
 
69
73
  // Analyze pending block transactions
70
74
  if (pendingBlock?.transactions && pendingBlock.transactions.length > 0) {
@@ -73,9 +77,7 @@ export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStrategy
73
77
  if (typeof tx === 'string') {
74
78
  return 0n;
75
79
  }
76
- const fee = tx.maxPriorityFeePerGas || 0n;
77
-
78
- return fee;
80
+ return tx.maxPriorityFeePerGas || 0n;
79
81
  })
80
82
  .filter((fee: bigint) => fee > 0n);
81
83
 
@@ -97,8 +99,8 @@ export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStrategy
97
99
  }
98
100
  }
99
101
 
100
- // Extract fee history from settled result
101
- const feeHistory = results.feeHistory.status === 'fulfilled' ? results.feeHistory.value : null;
102
+ // Extract fee history
103
+ const feeHistory = feeHistoryResult.status === 'fulfilled' ? feeHistoryResult.value : null;
102
104
 
103
105
  // Analyze fee history
104
106
  if (feeHistory?.reward && feeHistory.reward.length > 0) {
@@ -132,7 +134,7 @@ export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStrategy
132
134
  // Sanity check: cap competitive fee at 100x network estimate to avoid using unrealistic fees
133
135
  const maxReasonableFee = networkEstimate * 100n;
134
136
  if (competitiveFee > maxReasonableFee && networkEstimate > 0n) {
135
- logger?.warn('Competitive fee exceeds sanity cap, using capped value', {
137
+ logger?.debug('Competitive fee exceeds sanity cap, using capped value', {
136
138
  competitiveFee: formatGwei(competitiveFee),
137
139
  networkEstimate: formatGwei(networkEstimate),
138
140
  cappedTo: formatGwei(maxReasonableFee),
@@ -153,6 +155,8 @@ export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStrategy
153
155
 
154
156
  return {
155
157
  priorityFee: competitiveFee,
158
+ latestBlock,
159
+ blobBaseFee,
156
160
  debugInfo,
157
161
  };
158
162
  },