@aztec/ethereum 0.0.1-commit.24de95ac → 0.0.1-commit.2606882

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 (236) hide show
  1. package/dest/account.d.ts +1 -1
  2. package/dest/chain.d.ts +1 -1
  3. package/dest/client.d.ts +25 -3
  4. package/dest/client.d.ts.map +1 -1
  5. package/dest/client.js +60 -4
  6. package/dest/config.d.ts +29 -73
  7. package/dest/config.d.ts.map +1 -1
  8. package/dest/config.js +70 -387
  9. package/dest/constants.d.ts +1 -1
  10. package/dest/contracts/chain_state_override.d.ts +78 -0
  11. package/dest/contracts/chain_state_override.d.ts.map +1 -0
  12. package/dest/contracts/chain_state_override.js +137 -0
  13. package/dest/contracts/empire_base.d.ts +7 -5
  14. package/dest/contracts/empire_base.d.ts.map +1 -1
  15. package/dest/contracts/empire_base.js +1 -1
  16. package/dest/contracts/errors.d.ts +1 -1
  17. package/dest/contracts/errors.d.ts.map +1 -1
  18. package/dest/contracts/fee_asset_handler.d.ts +6 -5
  19. package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
  20. package/dest/contracts/fee_asset_handler.js +11 -9
  21. package/dest/contracts/fee_asset_price_oracle.d.ts +105 -0
  22. package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
  23. package/dest/contracts/fee_asset_price_oracle.js +656 -0
  24. package/dest/contracts/fee_juice.d.ts +1 -1
  25. package/dest/contracts/fee_juice.d.ts.map +1 -1
  26. package/dest/contracts/governance.d.ts +113 -36
  27. package/dest/contracts/governance.d.ts.map +1 -1
  28. package/dest/contracts/governance.js +207 -16
  29. package/dest/contracts/governance_proposer.d.ts +38 -4
  30. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  31. package/dest/contracts/governance_proposer.js +455 -12
  32. package/dest/contracts/gse.d.ts +1 -1
  33. package/dest/contracts/gse.d.ts.map +1 -1
  34. package/dest/contracts/inbox.d.ts +24 -3
  35. package/dest/contracts/inbox.d.ts.map +1 -1
  36. package/dest/contracts/inbox.js +42 -2
  37. package/dest/contracts/index.d.ts +6 -3
  38. package/dest/contracts/index.d.ts.map +1 -1
  39. package/dest/contracts/index.js +5 -2
  40. package/dest/contracts/log.d.ts +13 -0
  41. package/dest/contracts/log.d.ts.map +1 -0
  42. package/dest/contracts/log.js +1 -0
  43. package/dest/contracts/multicall.d.ts +127 -12
  44. package/dest/contracts/multicall.d.ts.map +1 -1
  45. package/dest/contracts/multicall.js +201 -93
  46. package/dest/contracts/outbox.d.ts +64 -0
  47. package/dest/contracts/outbox.d.ts.map +1 -0
  48. package/dest/contracts/outbox.js +113 -0
  49. package/dest/contracts/registry.d.ts +3 -1
  50. package/dest/contracts/registry.d.ts.map +1 -1
  51. package/dest/contracts/registry.js +30 -1
  52. package/dest/contracts/rollup.d.ts +5432 -131
  53. package/dest/contracts/rollup.d.ts.map +1 -1
  54. package/dest/contracts/rollup.js +1114 -231
  55. package/dest/contracts/slasher_contract.d.ts +1 -1
  56. package/dest/contracts/slasher_contract.d.ts.map +1 -1
  57. package/dest/contracts/{tally_slashing_proposer.d.ts → slashing_proposer.d.ts} +11 -10
  58. package/dest/contracts/slashing_proposer.d.ts.map +1 -0
  59. package/dest/contracts/{tally_slashing_proposer.js → slashing_proposer.js} +21 -16
  60. package/dest/contracts/utils.d.ts +1 -1
  61. package/dest/deploy_aztec_l1_contracts.d.ts +256 -0
  62. package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
  63. package/dest/deploy_aztec_l1_contracts.js +411 -0
  64. package/dest/deploy_l1_contract.d.ts +68 -0
  65. package/dest/deploy_l1_contract.d.ts.map +1 -0
  66. package/dest/deploy_l1_contract.js +312 -0
  67. package/dest/eth-signer/eth-signer.d.ts +1 -1
  68. package/dest/eth-signer/index.d.ts +1 -1
  69. package/dest/forwarder_proxy.d.ts +32 -0
  70. package/dest/forwarder_proxy.d.ts.map +1 -0
  71. package/dest/forwarder_proxy.js +93 -0
  72. package/dest/generated/l1-contracts-defaults.d.ts +30 -0
  73. package/dest/generated/l1-contracts-defaults.d.ts.map +1 -0
  74. package/dest/generated/l1-contracts-defaults.js +30 -0
  75. package/dest/l1_artifacts.d.ts +19816 -16730
  76. package/dest/l1_artifacts.d.ts.map +1 -1
  77. package/dest/l1_artifacts.js +9 -24
  78. package/dest/l1_contract_addresses.d.ts +61 -65
  79. package/dest/l1_contract_addresses.d.ts.map +1 -1
  80. package/dest/l1_contract_addresses.js +99 -80
  81. package/dest/l1_reader.d.ts +7 -5
  82. package/dest/l1_reader.d.ts.map +1 -1
  83. package/dest/l1_reader.js +15 -7
  84. package/dest/l1_tx_utils/config.d.ts +11 -5
  85. package/dest/l1_tx_utils/config.d.ts.map +1 -1
  86. package/dest/l1_tx_utils/config.js +43 -7
  87. package/dest/l1_tx_utils/constants.d.ts +8 -2
  88. package/dest/l1_tx_utils/constants.d.ts.map +1 -1
  89. package/dest/l1_tx_utils/constants.js +27 -2
  90. package/dest/l1_tx_utils/factory.d.ts +18 -10
  91. package/dest/l1_tx_utils/factory.d.ts.map +1 -1
  92. package/dest/l1_tx_utils/factory.js +17 -7
  93. package/dest/l1_tx_utils/fee-strategies/index.d.ts +10 -0
  94. package/dest/l1_tx_utils/fee-strategies/index.d.ts.map +1 -0
  95. package/dest/l1_tx_utils/fee-strategies/index.js +12 -0
  96. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts +8 -0
  97. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts.map +1 -0
  98. package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +129 -0
  99. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts +23 -0
  100. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts.map +1 -0
  101. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +191 -0
  102. package/dest/l1_tx_utils/fee-strategies/types.d.ts +51 -0
  103. package/dest/l1_tx_utils/fee-strategies/types.d.ts.map +1 -0
  104. package/dest/l1_tx_utils/fee-strategies/types.js +3 -0
  105. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +41 -0
  106. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -0
  107. package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +42 -0
  108. package/dest/l1_tx_utils/index-blobs.d.ts +3 -0
  109. package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -0
  110. package/dest/l1_tx_utils/index-blobs.js +2 -0
  111. package/dest/l1_tx_utils/index.d.ts +4 -1
  112. package/dest/l1_tx_utils/index.d.ts.map +1 -1
  113. package/dest/l1_tx_utils/index.js +3 -0
  114. package/dest/l1_tx_utils/interfaces.d.ts +2 -2
  115. package/dest/l1_tx_utils/interfaces.d.ts.map +1 -1
  116. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +233 -0
  117. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -0
  118. package/dest/l1_tx_utils/l1_fee_analyzer.js +506 -0
  119. package/dest/l1_tx_utils/l1_tx_utils.d.ts +26 -8
  120. package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
  121. package/dest/l1_tx_utils/l1_tx_utils.js +118 -70
  122. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +19 -30
  123. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
  124. package/dest/l1_tx_utils/readonly_l1_tx_utils.js +65 -168
  125. package/dest/l1_tx_utils/signer.d.ts +1 -1
  126. package/dest/l1_tx_utils/tx_delayer.d.ts +58 -0
  127. package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
  128. package/dest/{test → l1_tx_utils}/tx_delayer.js +70 -39
  129. package/dest/l1_tx_utils/types.d.ts +1 -1
  130. package/dest/l1_tx_utils/types.d.ts.map +1 -1
  131. package/dest/l1_tx_utils/utils.d.ts +1 -1
  132. package/dest/l1_types.d.ts +1 -1
  133. package/dest/publisher_manager.d.ts +21 -6
  134. package/dest/publisher_manager.d.ts.map +1 -1
  135. package/dest/publisher_manager.js +81 -7
  136. package/dest/queries.d.ts +14 -3
  137. package/dest/queries.d.ts.map +1 -1
  138. package/dest/queries.js +78 -9
  139. package/dest/test/chain_monitor.d.ts +48 -25
  140. package/dest/test/chain_monitor.d.ts.map +1 -1
  141. package/dest/test/chain_monitor.js +71 -38
  142. package/dest/test/eth_cheat_codes.d.ts +22 -6
  143. package/dest/test/eth_cheat_codes.d.ts.map +1 -1
  144. package/dest/test/eth_cheat_codes.js +28 -7
  145. package/dest/test/eth_cheat_codes_with_state.d.ts +1 -1
  146. package/dest/test/eth_cheat_codes_with_state.d.ts.map +1 -1
  147. package/dest/test/index.d.ts +1 -3
  148. package/dest/test/index.d.ts.map +1 -1
  149. package/dest/test/index.js +0 -2
  150. package/dest/test/rollup_cheat_codes.d.ts +46 -14
  151. package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
  152. package/dest/test/rollup_cheat_codes.js +118 -42
  153. package/dest/test/start_anvil.d.ts +25 -2
  154. package/dest/test/start_anvil.d.ts.map +1 -1
  155. package/dest/test/start_anvil.js +143 -28
  156. package/dest/test/upgrade_utils.d.ts +1 -1
  157. package/dest/test/upgrade_utils.js +2 -2
  158. package/dest/types.d.ts +57 -2
  159. package/dest/types.d.ts.map +1 -1
  160. package/dest/utils.d.ts +24 -4
  161. package/dest/utils.d.ts.map +1 -1
  162. package/dest/utils.js +112 -16
  163. package/dest/zkPassportVerifierAddress.d.ts +1 -1
  164. package/package.json +35 -17
  165. package/src/client.ts +66 -2
  166. package/src/config.ts +91 -469
  167. package/src/contracts/README.md +157 -0
  168. package/src/contracts/chain_state_override.ts +200 -0
  169. package/src/contracts/empire_base.ts +6 -5
  170. package/src/contracts/fee_asset_handler.ts +10 -7
  171. package/src/contracts/fee_asset_price_oracle.ts +285 -0
  172. package/src/contracts/governance.ts +279 -13
  173. package/src/contracts/governance_proposer.ts +74 -7
  174. package/src/contracts/inbox.ts +64 -4
  175. package/src/contracts/index.ts +5 -2
  176. package/src/contracts/log.ts +13 -0
  177. package/src/contracts/multicall.ts +243 -102
  178. package/src/contracts/outbox.ts +132 -0
  179. package/src/contracts/registry.ts +31 -1
  180. package/src/contracts/rollup.ts +819 -192
  181. package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +26 -21
  182. package/src/deploy_aztec_l1_contracts.ts +646 -0
  183. package/src/deploy_l1_contract.ts +362 -0
  184. package/src/forwarder_proxy.ts +108 -0
  185. package/src/generated/l1-contracts-defaults.ts +32 -0
  186. package/src/l1_artifacts.ts +12 -35
  187. package/src/l1_contract_addresses.ts +120 -92
  188. package/src/l1_reader.ts +25 -10
  189. package/src/l1_tx_utils/config.ts +52 -11
  190. package/src/l1_tx_utils/constants.ts +13 -2
  191. package/src/l1_tx_utils/factory.ts +31 -31
  192. package/src/l1_tx_utils/fee-strategies/index.ts +22 -0
  193. package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +163 -0
  194. package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +245 -0
  195. package/src/l1_tx_utils/fee-strategies/types.ts +56 -0
  196. package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +108 -0
  197. package/src/l1_tx_utils/index-blobs.ts +2 -0
  198. package/src/l1_tx_utils/index.ts +3 -0
  199. package/src/l1_tx_utils/interfaces.ts +1 -1
  200. package/src/l1_tx_utils/l1_fee_analyzer.ts +803 -0
  201. package/src/l1_tx_utils/l1_tx_utils.ts +123 -52
  202. package/src/l1_tx_utils/readonly_l1_tx_utils.ts +79 -214
  203. package/src/{test → l1_tx_utils}/tx_delayer.ts +97 -58
  204. package/src/publisher_manager.ts +107 -10
  205. package/src/queries.ts +87 -10
  206. package/src/test/chain_monitor.ts +115 -51
  207. package/src/test/eth_cheat_codes.ts +25 -7
  208. package/src/test/index.ts +0 -2
  209. package/src/test/rollup_cheat_codes.ts +123 -45
  210. package/src/test/start_anvil.ts +179 -27
  211. package/src/test/upgrade_utils.ts +2 -2
  212. package/src/types.ts +62 -0
  213. package/src/utils.ts +128 -19
  214. package/dest/contracts/empire_slashing_proposer.d.ts +0 -65
  215. package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
  216. package/dest/contracts/empire_slashing_proposer.js +0 -194
  217. package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
  218. package/dest/deploy_l1_contracts.d.ts +0 -226
  219. package/dest/deploy_l1_contracts.d.ts.map +0 -1
  220. package/dest/deploy_l1_contracts.js +0 -1473
  221. package/dest/index.d.ts +0 -18
  222. package/dest/index.d.ts.map +0 -1
  223. package/dest/index.js +0 -17
  224. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +0 -26
  225. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +0 -1
  226. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +0 -26
  227. package/dest/test/delayed_tx_utils.d.ts +0 -13
  228. package/dest/test/delayed_tx_utils.d.ts.map +0 -1
  229. package/dest/test/delayed_tx_utils.js +0 -28
  230. package/dest/test/tx_delayer.d.ts +0 -36
  231. package/dest/test/tx_delayer.d.ts.map +0 -1
  232. package/src/contracts/empire_slashing_proposer.ts +0 -259
  233. package/src/deploy_l1_contracts.ts +0 -1849
  234. package/src/index.ts +0 -17
  235. package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
  236. package/src/test/delayed_tx_utils.ts +0 -52
@@ -1,4 +1,6 @@
1
- import { InboxContract, type RollupContract } from '@aztec/ethereum/contracts';
1
+ import type { ManaMinFeeComponents, RollupContract } from '@aztec/ethereum/contracts';
2
+ import { InboxContract } from '@aztec/ethereum/contracts';
3
+ import { CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
2
4
  import { EthAddress } from '@aztec/foundation/eth-address';
3
5
  import { createLogger } from '@aztec/foundation/log';
4
6
  import { promiseWithResolvers } from '@aztec/foundation/promise';
@@ -8,13 +10,30 @@ import { EventEmitter } from 'events';
8
10
 
9
11
  import type { ViemClient } from '../types.js';
10
12
 
13
+ /** L2 fee data reported by the chain monitor. */
14
+ export type L2FeeData = ManaMinFeeComponents & {
15
+ /** Total minimum fee per mana in Fee Juice (sum of sequencerCost + proverCost + congestionCost). */
16
+ minFeePerMana: bigint;
17
+ /** L1 base fee observed by the oracle. */
18
+ l1BaseFee: bigint;
19
+ /** L1 blob fee observed by the oracle. */
20
+ l1BlobFee: bigint;
21
+ /** ETH per fee asset exchange rate (1e12 precision). */
22
+ ethPerFeeAsset: bigint;
23
+ /** Mana target per checkpoint. */
24
+ manaTarget: bigint;
25
+ };
26
+
11
27
  export type ChainMonitorEventMap = {
12
28
  'l1-block': [{ l1BlockNumber: number; timestamp: bigint }];
13
- 'l2-block': [{ l2BlockNumber: number; l1BlockNumber: number; l2SlotNumber: number; timestamp: bigint }];
14
- 'l2-block-proven': [{ l2ProvenBlockNumber: number; l1BlockNumber: number; timestamp: bigint }];
29
+ checkpoint: [
30
+ { checkpointNumber: CheckpointNumber; l1BlockNumber: number; l2SlotNumber: SlotNumber; timestamp: bigint },
31
+ ];
32
+ 'checkpoint-proven': [{ provenCheckpointNumber: CheckpointNumber; l1BlockNumber: number; timestamp: bigint }];
15
33
  'l2-messages': [{ totalL2Messages: number; l1BlockNumber: number }];
16
- 'l2-epoch': [{ l2EpochNumber: number; timestamp: bigint; committee: EthAddress[] | undefined }];
17
- 'l2-slot': [{ l2SlotNumber: number; timestamp: bigint }];
34
+ 'l2-epoch': [{ l2EpochNumber: EpochNumber; timestamp: bigint; committee: EthAddress[] | undefined }];
35
+ 'l2-slot': [{ l2SlotNumber: SlotNumber; timestamp: bigint }];
36
+ 'l2-fees': [L2FeeData];
18
37
  };
19
38
 
20
39
  /** Utility class that polls the chain on quick intervals and logs new L1 blocks, L2 blocks, and L2 proofs. */
@@ -27,20 +46,22 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
27
46
 
28
47
  /** Current L1 block number */
29
48
  public l1BlockNumber!: number;
30
- /** Current L2 block number */
31
- public l2BlockNumber!: number;
32
- /** Current L2 proven block number */
33
- public l2ProvenBlockNumber!: number;
34
- /** L1 timestamp for the current L2 block */
35
- public l2BlockTimestamp!: bigint;
36
- /** L1 timestamp for the proven L2 block */
37
- public l2ProvenBlockTimestamp!: bigint;
49
+ /** Current checkpoint number */
50
+ public checkpointNumber!: CheckpointNumber;
51
+ /** Current proven checkpoint number */
52
+ public provenCheckpointNumber!: CheckpointNumber;
53
+ /** L1 timestamp for the current checkpoint */
54
+ public checkpointTimestamp!: bigint;
55
+ /** L1 timestamp for the proven checkpoint */
56
+ public provenCheckpointTimestamp!: bigint;
38
57
  /** Total number of L2 messages pushed into the Inbox */
39
58
  public totalL2Messages: number = 0;
40
59
  /** Current L2 epoch number */
41
- public l2EpochNumber!: bigint;
60
+ public l2EpochNumber!: EpochNumber;
42
61
  /** Current L2 slot number */
43
- public l2SlotNumber!: bigint;
62
+ public l2SlotNumber!: SlotNumber;
63
+ /** Current L2 fee data (components of the minimum fee per mana). */
64
+ public l2FeeData!: L2FeeData;
44
65
 
45
66
  constructor(
46
67
  private readonly rollup: RollupContract,
@@ -73,7 +94,7 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
73
94
  }
74
95
  }
75
96
 
76
- private async getInbox() {
97
+ protected async getInbox() {
77
98
  if (!this.inbox) {
78
99
  const { inboxAddress } = await this.rollup.getRollupAddresses();
79
100
  this.inbox = new InboxContract(this.l1Client, inboxAddress);
@@ -114,28 +135,28 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
114
135
  this.emit('l1-block', { l1BlockNumber: newL1BlockNumber, timestamp });
115
136
  let msg = `L1 block ${newL1BlockNumber} mined at ${timestampString}`;
116
137
 
117
- const newL2BlockNumber = Number(await this.rollup.getBlockNumber());
118
- if (this.l2BlockNumber !== newL2BlockNumber) {
119
- const epochNumber = await this.rollup.getEpochNumberForBlock(BigInt(newL2BlockNumber));
120
- msg += ` with new L2 block ${newL2BlockNumber} for epoch ${epochNumber}`;
121
- this.l2BlockNumber = newL2BlockNumber;
122
- this.l2BlockTimestamp = timestamp;
123
- this.emit('l2-block', {
124
- l2BlockNumber: newL2BlockNumber,
138
+ const newCheckpointNumber = await this.rollup.getCheckpointNumber();
139
+ if (this.checkpointNumber !== newCheckpointNumber) {
140
+ const epochNumber = await this.rollup.getEpochNumberForCheckpoint(newCheckpointNumber);
141
+ msg += ` with new checkpoint ${newCheckpointNumber} for epoch ${epochNumber}`;
142
+ this.checkpointNumber = newCheckpointNumber;
143
+ this.checkpointTimestamp = timestamp;
144
+ this.emit('checkpoint', {
145
+ checkpointNumber: newCheckpointNumber,
125
146
  l1BlockNumber: newL1BlockNumber,
126
- l2SlotNumber: Number(l2SlotNumber),
147
+ l2SlotNumber,
127
148
  timestamp,
128
149
  });
129
150
  }
130
151
 
131
- const newL2ProvenBlockNumber = Number(await this.rollup.getProvenBlockNumber());
132
- if (this.l2ProvenBlockNumber !== newL2ProvenBlockNumber) {
133
- const epochNumber = await this.rollup.getEpochNumberForBlock(BigInt(newL2ProvenBlockNumber));
134
- msg += ` with proof up to L2 block ${newL2ProvenBlockNumber} for epoch ${epochNumber}`;
135
- this.l2ProvenBlockNumber = newL2ProvenBlockNumber;
136
- this.l2ProvenBlockTimestamp = timestamp;
137
- this.emit('l2-block-proven', {
138
- l2ProvenBlockNumber: newL2ProvenBlockNumber,
152
+ const newProvenCheckpointNumber = await this.rollup.getProvenCheckpointNumber();
153
+ if (this.provenCheckpointNumber !== newProvenCheckpointNumber) {
154
+ const epochNumber = await this.rollup.getEpochNumberForCheckpoint(newProvenCheckpointNumber);
155
+ msg += ` with proof up to checkpoint ${newProvenCheckpointNumber} for epoch ${epochNumber}`;
156
+ this.provenCheckpointNumber = newProvenCheckpointNumber;
157
+ this.provenCheckpointTimestamp = timestamp;
158
+ this.emit('checkpoint-proven', {
159
+ provenCheckpointNumber: newProvenCheckpointNumber,
139
160
  l1BlockNumber: newL1BlockNumber,
140
161
  timestamp,
141
162
  });
@@ -152,14 +173,21 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
152
173
  let committee: EthAddress[] | undefined;
153
174
  if (l2Epoch !== this.l2EpochNumber) {
154
175
  this.l2EpochNumber = l2Epoch;
155
- committee = (await this.rollup.getCurrentEpochCommittee())?.map(addr => EthAddress.fromString(addr));
156
- this.emit('l2-epoch', { l2EpochNumber: Number(l2Epoch), timestamp, committee });
157
- msg += ` starting new epoch ${this.l2EpochNumber} `;
176
+ committee = await this.rollup.getCurrentEpochCommittee();
177
+ this.emit('l2-epoch', { l2EpochNumber: l2Epoch, timestamp, committee });
178
+ msg += ` starting new epoch ${this.l2EpochNumber}`;
158
179
  }
159
180
 
160
181
  if (l2SlotNumber !== this.l2SlotNumber) {
161
182
  this.l2SlotNumber = l2SlotNumber;
162
- this.emit('l2-slot', { l2SlotNumber: Number(l2SlotNumber), timestamp });
183
+ this.emit('l2-slot', { l2SlotNumber, timestamp });
184
+ }
185
+
186
+ const feeData = await this.fetchFeeData(timestamp);
187
+ if (this.hasFeeDataChanged(feeData)) {
188
+ msg += ` with L2 min fee ${feeData.minFeePerMana}`;
189
+ this.l2FeeData = feeData;
190
+ this.emit('l2-fees', feeData);
163
191
  }
164
192
 
165
193
  this.logger.info(msg, {
@@ -168,23 +196,23 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
168
196
  l1BlockNumber: this.l1BlockNumber,
169
197
  l2SlotNumber,
170
198
  l2Epoch,
171
- l2BlockNumber: this.l2BlockNumber,
172
- l2ProvenBlockNumber: this.l2ProvenBlockNumber,
199
+ checkpointNumber: this.checkpointNumber,
200
+ provenCheckpointNumber: this.provenCheckpointNumber,
173
201
  totalL2Messages: this.totalL2Messages,
174
202
  committee,
203
+ ...this.l2FeeData,
175
204
  });
176
205
 
177
206
  return this;
178
207
  }
179
208
 
180
- public waitUntilL2Slot(slot: number | bigint): Promise<void> {
181
- const targetSlot = typeof slot === 'bigint' ? slot.valueOf() : slot;
182
- if (this.l2SlotNumber >= targetSlot) {
209
+ public waitUntilL2Slot(slot: SlotNumber): Promise<void> {
210
+ if (this.l2SlotNumber >= slot) {
183
211
  return Promise.resolve();
184
212
  }
185
213
  return new Promise(resolve => {
186
- const listener = (data: { l2SlotNumber: number; timestamp: bigint }) => {
187
- if (data.l2SlotNumber >= targetSlot) {
214
+ const listener = (data: { l2SlotNumber: SlotNumber; timestamp: bigint }) => {
215
+ if (data.l2SlotNumber >= slot) {
188
216
  this.off('l2-slot', listener);
189
217
  resolve();
190
218
  }
@@ -193,6 +221,11 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
193
221
  });
194
222
  }
195
223
 
224
+ public async waitUntilNextL2Slot(): Promise<void> {
225
+ const targetSlot = SlotNumber.add((await this.run()).l2SlotNumber, 1);
226
+ return this.waitUntilL2Slot(targetSlot);
227
+ }
228
+
196
229
  public waitUntilL1Block(block: number | bigint): Promise<void> {
197
230
  const targetBlock = typeof block === 'bigint' ? block.valueOf() : block;
198
231
  if (this.l1BlockNumber >= targetBlock) {
@@ -225,19 +258,50 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
225
258
  });
226
259
  }
227
260
 
228
- public waitUntilL2Block(l2BlockNumber: number | bigint): Promise<void> {
229
- const targetBlock = typeof l2BlockNumber === 'bigint' ? l2BlockNumber.valueOf() : l2BlockNumber;
230
- if (this.l2BlockNumber >= targetBlock) {
261
+ public waitUntilCheckpoint(checkpointNumber: CheckpointNumber): Promise<void> {
262
+ if (this.checkpointNumber >= checkpointNumber) {
231
263
  return Promise.resolve();
232
264
  }
233
265
  return new Promise(resolve => {
234
- const listener = (data: { l2BlockNumber: number; timestamp: bigint }) => {
235
- if (data.l2BlockNumber >= targetBlock) {
236
- this.off('l2-block', listener);
266
+ const listener = (data: { checkpointNumber: CheckpointNumber; timestamp: bigint }) => {
267
+ if (data.checkpointNumber >= checkpointNumber) {
268
+ this.off('checkpoint', listener);
237
269
  resolve();
238
270
  }
239
271
  };
240
- this.on('l2-block', listener);
272
+ this.on('checkpoint', listener);
241
273
  });
242
274
  }
275
+
276
+ private async fetchFeeData(timestamp: bigint): Promise<L2FeeData> {
277
+ const [components, minFeePerMana, l1Fees, ethPerFeeAsset, manaTarget] = await Promise.all([
278
+ this.rollup.getManaMinFeeComponentsAt(timestamp, true),
279
+ this.rollup.getManaMinFeeAt(timestamp, true),
280
+ this.rollup.getL1FeesAt(timestamp),
281
+ this.rollup.getEthPerFeeAsset(),
282
+ this.rollup.getManaTarget(),
283
+ ]);
284
+ return {
285
+ ...components,
286
+ minFeePerMana,
287
+ l1BaseFee: l1Fees.baseFee,
288
+ l1BlobFee: l1Fees.blobFee,
289
+ ethPerFeeAsset,
290
+ manaTarget,
291
+ };
292
+ }
293
+
294
+ private hasFeeDataChanged(newData: L2FeeData): boolean {
295
+ if (!this.l2FeeData) {
296
+ return true;
297
+ }
298
+ return (
299
+ this.l2FeeData.sequencerCost !== newData.sequencerCost ||
300
+ this.l2FeeData.proverCost !== newData.proverCost ||
301
+ this.l2FeeData.congestionCost !== newData.congestionCost ||
302
+ this.l2FeeData.l1BaseFee !== newData.l1BaseFee ||
303
+ this.l2FeeData.l1BlobFee !== newData.l1BlobFee ||
304
+ this.l2FeeData.ethPerFeeAsset !== newData.ethPerFeeAsset
305
+ );
306
+ }
243
307
  }
@@ -1,12 +1,13 @@
1
1
  import { toBigIntBE, toHex } from '@aztec/foundation/bigint-buffer';
2
- import { keccak256 } from '@aztec/foundation/crypto';
2
+ import { keccak256 } from '@aztec/foundation/crypto/keccak';
3
3
  import { EthAddress } from '@aztec/foundation/eth-address';
4
4
  import { jsonStringify } from '@aztec/foundation/json-rpc';
5
5
  import { createLogger } from '@aztec/foundation/log';
6
6
  import { pluralize } from '@aztec/foundation/string';
7
7
  import type { DateProvider, TestDateProvider } from '@aztec/foundation/timer';
8
8
 
9
- import { type Hex, type Transaction, createPublicClient, fallback, hexToNumber, http } from 'viem';
9
+ import { type Chain, type Hex, type Transaction, createPublicClient, fallback, hexToNumber, http } from 'viem';
10
+ import { foundry } from 'viem/chains';
10
11
 
11
12
  import type { ViemPublicClient } from '../types.js';
12
13
 
@@ -28,9 +29,14 @@ export class EthCheatCodes {
28
29
  * The logger to use for the eth cheatcodes
29
30
  */
30
31
  public logger = createLogger('ethereum:cheat_codes'),
32
+ /**
33
+ * The chain configuration provided to Anvil
34
+ */
35
+ public chain: Chain = foundry,
31
36
  ) {
32
37
  this.publicClient = createPublicClient({
33
- transport: fallback(this.rpcUrls.map(url => http(url))),
38
+ transport: fallback(this.rpcUrls.map(url => http(url, { batch: false }))),
39
+ chain: chain,
34
40
  });
35
41
  }
36
42
 
@@ -79,14 +85,26 @@ export class EthCheatCodes {
79
85
  }
80
86
 
81
87
  /**
82
- * Get the current timestamp
83
- * @returns The current timestamp
88
+ * Get the timestamp of the latest mined L1 block.
89
+ * Note: this is NOT the current time — it's the discrete timestamp of the last block.
90
+ * Between blocks, the actual chain time advances but no new block reflects it.
91
+ * @returns The latest block timestamp in seconds
84
92
  */
85
- public async timestamp(): Promise<number> {
93
+ public async lastBlockTimestamp(): Promise<number> {
86
94
  const res = await this.doRpcCall('eth_getBlockByNumber', ['latest', true]);
87
95
  return parseInt(res.timestamp, 16);
88
96
  }
89
97
 
98
+ /**
99
+ * Get the timestamp of the pending L1 block — the block that anvil will mine next.
100
+ * Reflects any prior `setNextBlockTimestamp` call or the configured block interval.
101
+ * @returns The pending block timestamp in seconds.
102
+ */
103
+ public async nextBlockTimestamp(): Promise<number> {
104
+ const res = await this.doRpcCall('eth_getBlockByNumber', ['pending', false]);
105
+ return parseInt(res.timestamp, 16);
106
+ }
107
+
90
108
  /**
91
109
  * Advance the chain by a number of blocks
92
110
  * @param numberOfBlocks - The number of blocks to mine
@@ -546,7 +564,7 @@ export class EthCheatCodes {
546
564
  }
547
565
 
548
566
  public async syncDateProvider() {
549
- const timestamp = await this.timestamp();
567
+ const timestamp = await this.lastBlockTimestamp();
550
568
  if ('setTime' in this.dateProvider) {
551
569
  this.dateProvider.setTime(timestamp * 1000);
552
570
  }
package/src/test/index.ts CHANGED
@@ -1,8 +1,6 @@
1
- export * from './delayed_tx_utils.js';
2
1
  export * from './eth_cheat_codes.js';
3
2
  export * from './eth_cheat_codes_with_state.js';
4
3
  export * from './start_anvil.js';
5
- export * from './tx_delayer.js';
6
4
  export * from './upgrade_utils.js';
7
5
  export * from './chain_monitor.js';
8
6
  export * from './rollup_cheat_codes.js';
@@ -1,5 +1,7 @@
1
- import { RollupContract, type ViemPublicClient } from '@aztec/ethereum';
1
+ import { OutboxContract, RollupContract } from '@aztec/ethereum/contracts';
2
2
  import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
3
+ import type { ViemPublicClient } from '@aztec/ethereum/types';
4
+ import { CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
3
5
  import { EthAddress } from '@aztec/foundation/eth-address';
4
6
  import { createLogger } from '@aztec/foundation/log';
5
7
  import type { DateProvider } from '@aztec/foundation/timer';
@@ -13,8 +15,8 @@ import {
13
15
  getContract,
14
16
  hexToBigInt,
15
17
  http,
18
+ keccak256,
16
19
  } from 'viem';
17
- import { foundry } from 'viem/chains';
18
20
 
19
21
  import { EthCheatCodes } from './eth_cheat_codes.js';
20
22
 
@@ -30,8 +32,8 @@ export class RollupCheatCodes {
30
32
  addresses: Pick<L1ContractAddresses, 'rollupAddress'>,
31
33
  ) {
32
34
  this.client = createPublicClient({
33
- chain: foundry,
34
- transport: fallback(ethCheatCodes.rpcUrls.map(url => http(url))),
35
+ chain: ethCheatCodes.chain,
36
+ transport: fallback(ethCheatCodes.rpcUrls.map(url => http(url, { batch: false }))),
35
37
  });
36
38
  this.rollup = getContract({
37
39
  abi: RollupAbi,
@@ -50,15 +52,34 @@ export class RollupCheatCodes {
50
52
  }
51
53
 
52
54
  /** Returns the current slot */
53
- public async getSlot() {
55
+ public async getSlot(): Promise<SlotNumber> {
54
56
  const ts = BigInt((await this.client.getBlock()).timestamp);
55
- return await this.rollup.read.getSlotAt([ts]);
57
+ return this.getSlotAt(ts);
58
+ }
59
+
60
+ /** Returns the slot number at a given timestamp. */
61
+ public async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
62
+ return SlotNumber.fromBigInt(await this.rollup.read.getSlotAt([timestamp]));
63
+ }
64
+
65
+ /** Returns the timestamp for the start of a given slot. */
66
+ public async getTimestampForSlot(slot: SlotNumber): Promise<bigint> {
67
+ return await this.rollup.read.getTimestampForSlot([BigInt(slot)]);
68
+ }
69
+
70
+ /** Returns the number of seconds until the start of the given slot based on L1 block timestamp. */
71
+ public async getSecondsUntilSlot(slot: SlotNumber): Promise<number> {
72
+ const [currentTimestamp, targetTimestamp] = await Promise.all([
73
+ this.client.getBlock().then(b => BigInt(b.timestamp)),
74
+ this.rollup.read.getTimestampForSlot([BigInt(slot)]),
75
+ ]);
76
+ return Math.max(0, Number(targetTimestamp - currentTimestamp));
56
77
  }
57
78
 
58
79
  /** Returns the current epoch */
59
- public async getEpoch() {
80
+ public async getEpoch(): Promise<EpochNumber> {
60
81
  const slotNumber = await this.getSlot();
61
- return await this.rollup.read.getEpochAtSlot([slotNumber]);
82
+ return EpochNumber.fromBigInt(await this.rollup.read.getEpochAtSlot([BigInt(slotNumber)]));
62
83
  }
63
84
 
64
85
  /**
@@ -66,13 +87,13 @@ export class RollupCheatCodes {
66
87
  * @returns The pending and proven chain tips
67
88
  */
68
89
  public async getTips(): Promise<{
69
- /** The pending chain tip */ pending: bigint;
70
- /** The proven chain tip */ proven: bigint;
90
+ /** The pending chain tip */ pending: CheckpointNumber;
91
+ /** The proven chain tip */ proven: CheckpointNumber;
71
92
  }> {
72
- const res = await this.rollup.read.getTips();
93
+ const { pending, proven } = await this.rollup.read.getTips();
73
94
  return {
74
- pending: res.pendingBlockNumber,
75
- proven: res.provenBlockNumber,
95
+ pending: CheckpointNumber.fromBigInt(pending),
96
+ proven: CheckpointNumber.fromBigInt(proven),
76
97
  };
77
98
  }
78
99
 
@@ -81,16 +102,16 @@ export class RollupCheatCodes {
81
102
  */
82
103
  public async debugRollup() {
83
104
  const rollup = new RollupContract(this.client, this.rollup.address);
84
- const pendingNum = await rollup.getBlockNumber();
85
- const provenNum = await rollup.getProvenBlockNumber();
105
+ const pendingNum = await rollup.getCheckpointNumber();
106
+ const provenNum = await rollup.getProvenCheckpointNumber();
86
107
  const validators = await rollup.getAttesters();
87
108
  const committee = await rollup.getCurrentEpochCommittee();
88
109
  const archive = await rollup.archive();
89
110
  const slot = await this.getSlot();
90
111
  const epochNum = await rollup.getEpochNumberForSlotNumber(slot);
91
112
 
92
- this.logger.info(`Pending block num: ${pendingNum}`);
93
- this.logger.info(`Proven block num: ${provenNum}`);
113
+ this.logger.info(`Pending checkpoint num: ${pendingNum}`);
114
+ this.logger.info(`Proven checkpoint num: ${provenNum}`);
94
115
  this.logger.info(`Validators: ${validators.map(v => v.toString()).join(', ')}`);
95
116
  this.logger.info(`Committee: ${committee?.map(v => v.toString()).join(', ')}`);
96
117
  this.logger.info(`Archive: ${archive}`);
@@ -101,13 +122,13 @@ export class RollupCheatCodes {
101
122
  /** Fetches the epoch and slot duration config from the rollup contract */
102
123
  public async getConfig(): Promise<{
103
124
  /** Epoch duration */ epochDuration: bigint;
104
- /** Slot duration */ slotDuration: bigint;
125
+ /** Slot duration */ slotDuration: number;
105
126
  }> {
106
127
  const [epochDuration, slotDuration] = await Promise.all([
107
128
  this.rollup.read.getEpochDuration(),
108
129
  this.rollup.read.getSlotDuration(),
109
130
  ]);
110
- return { epochDuration, slotDuration };
131
+ return { epochDuration, slotDuration: Number(slotDuration) };
111
132
  }
112
133
 
113
134
  /**
@@ -116,18 +137,18 @@ export class RollupCheatCodes {
116
137
  * @param opts - Options
117
138
  */
118
139
  public async advanceToEpoch(
119
- epoch: bigint | number,
140
+ epoch: EpochNumber,
120
141
  opts: {
121
142
  /** Offset in seconds */
122
143
  offset?: number;
123
144
  } = {},
124
145
  ) {
125
146
  const { epochDuration: slotsInEpoch } = await this.getConfig();
126
- const timestamp =
127
- (await this.rollup.read.getTimestampForSlot([BigInt(epoch) * slotsInEpoch])) + BigInt(opts.offset ?? 0);
147
+ const slotNumber = SlotNumber(Number(epoch) * Number(slotsInEpoch));
148
+ const timestamp = (await this.rollup.read.getTimestampForSlot([BigInt(slotNumber)])) + BigInt(opts.offset ?? 0);
128
149
  try {
129
150
  await this.ethCheatCodes.warp(Number(timestamp), { ...opts, silent: true, resetBlockInterval: true });
130
- this.logger.warn(`Warped to epoch ${epoch}`);
151
+ this.logger.warn(`Warped to epoch ${epoch}`, { offset: opts.offset, timestamp });
131
152
  } catch (err) {
132
153
  this.logger.warn(`Warp to epoch ${epoch} failed: ${err}`);
133
154
  }
@@ -138,8 +159,8 @@ export class RollupCheatCodes {
138
159
  public async advanceToNextEpoch() {
139
160
  const slot = await this.getSlot();
140
161
  const { epochDuration, slotDuration } = await this.getConfig();
141
- const slotsUntilNextEpoch = epochDuration - (slot % epochDuration) + 1n;
142
- const timeToNextEpoch = slotsUntilNextEpoch * slotDuration;
162
+ const slotsUntilNextEpoch = epochDuration - (BigInt(slot) % epochDuration) + 1n;
163
+ const timeToNextEpoch = slotsUntilNextEpoch * BigInt(slotDuration);
143
164
  const l1Timestamp = BigInt((await this.client.getBlock()).timestamp);
144
165
  await this.ethCheatCodes.warp(Number(l1Timestamp + timeToNextEpoch), {
145
166
  silent: true,
@@ -151,10 +172,26 @@ export class RollupCheatCodes {
151
172
  /** Warps time in L1 until the beginning of the next slot. */
152
173
  public async advanceToNextSlot() {
153
174
  const currentSlot = await this.getSlot();
154
- const timestamp = await this.rollup.read.getTimestampForSlot([currentSlot + 1n]);
175
+ const nextSlot = SlotNumber(currentSlot + 1);
176
+ const timestamp = await this.rollup.read.getTimestampForSlot([BigInt(nextSlot)]);
155
177
  await this.ethCheatCodes.warp(Number(timestamp), { silent: true, resetBlockInterval: true });
156
- this.logger.warn(`Advanced to slot ${currentSlot + 1n}`);
157
- return [timestamp, currentSlot + 1n];
178
+ this.logger.warn(`Advanced to slot ${nextSlot}`);
179
+ return [timestamp, nextSlot];
180
+ }
181
+
182
+ /**
183
+ * Warps L1 time to the start of an explicit absolute slot. Unlike `advanceSlots(N)` which is
184
+ * relative to the current L1 timestamp at call time and therefore races with real-time
185
+ * progression between query and warp, this lands at the slot regardless of latency.
186
+ *
187
+ * Throws if the requested slot is in the past relative to current L1 time (anvil cannot
188
+ * rewind).
189
+ */
190
+ public async advanceToSlot(slot: SlotNumber) {
191
+ const timestamp = await this.rollup.read.getTimestampForSlot([BigInt(slot)]);
192
+ await this.ethCheatCodes.warp(Number(timestamp), { silent: true, resetBlockInterval: true });
193
+ this.logger.warn(`Advanced to slot ${slot}`, { timestamp });
194
+ return timestamp;
158
195
  }
159
196
 
160
197
  /**
@@ -163,42 +200,42 @@ export class RollupCheatCodes {
163
200
  */
164
201
  public async advanceSlots(howMany: number) {
165
202
  const l1Timestamp = (await this.client.getBlock()).timestamp;
166
- const slotDuration = await this.rollup.read.getSlotDuration();
167
- const timeToWarp = BigInt(howMany) * slotDuration;
203
+ const slotDuration = Number(await this.rollup.read.getSlotDuration());
204
+ const timeToWarp = BigInt(howMany) * BigInt(slotDuration);
168
205
  await this.ethCheatCodes.warp(l1Timestamp + timeToWarp, { silent: true, resetBlockInterval: true });
169
206
  const [slot, epoch] = await Promise.all([this.getSlot(), this.getEpoch()]);
170
207
  this.logger.warn(`Advanced ${howMany} slots up to slot ${slot} in epoch ${epoch}`);
171
208
  }
172
209
 
173
210
  /**
174
- * Marks the specified block (or latest if none) as proven
175
- * @param maybeBlockNumber - The block number to mark as proven (defaults to latest pending)
211
+ * Marks the specified checkpoint (or latest if none) as proven
212
+ * @param maybeCheckpointNumber - The checkpoint number to mark as proven (defaults to latest pending)
176
213
  */
177
- public markAsProven(maybeBlockNumber?: number | bigint) {
214
+ public markAsProven(maybeCheckpointNumber?: CheckpointNumber) {
178
215
  return this.ethCheatCodes.execWithPausedAnvil(async () => {
179
216
  const tipsBefore = await this.getTips();
180
217
  const { pending, proven } = tipsBefore;
181
218
 
182
- let blockNumber = maybeBlockNumber;
183
- if (blockNumber === undefined || blockNumber > pending) {
184
- blockNumber = pending;
219
+ let checkpointNumber = maybeCheckpointNumber;
220
+ if (checkpointNumber === undefined || checkpointNumber > pending) {
221
+ checkpointNumber = pending;
185
222
  }
186
- if (blockNumber <= proven) {
187
- this.logger.debug(`Block ${blockNumber} is already proven`);
223
+ if (checkpointNumber <= proven) {
224
+ this.logger.debug(`Checkpoint ${checkpointNumber} is already proven`);
188
225
  return;
189
226
  }
190
227
 
191
228
  // @note @LHerskind this is heavily dependent on the storage layout and size of values
192
229
  // The rollupStore is a struct and if the size of elements or the struct changes, this can break
193
- const provenBlockNumberSlot = hexToBigInt(RollupContract.stfStorageSlot);
230
+ const provenCheckpointNumberSlot = hexToBigInt(RollupContract.stfStorageSlot);
194
231
 
195
232
  // Need to pack it as a single 32 byte word
196
- const newValue = (BigInt(tipsBefore.pending) << 128n) | BigInt(blockNumber);
197
- await this.ethCheatCodes.store(EthAddress.fromString(this.rollup.address), provenBlockNumberSlot, newValue);
233
+ const newValue = (BigInt(tipsBefore.pending) << 128n) | BigInt(checkpointNumber);
234
+ await this.ethCheatCodes.store(EthAddress.fromString(this.rollup.address), provenCheckpointNumberSlot, newValue);
198
235
 
199
236
  const tipsAfter = await this.getTips();
200
237
  if (tipsAfter.pending < tipsAfter.proven) {
201
- throw new Error('Overwrote pending tip to a block in the past');
238
+ throw new Error('Overwrote pending tip to a checkpoint in the past');
202
239
  }
203
240
 
204
241
  this.logger.info(
@@ -209,7 +246,7 @@ export class RollupCheatCodes {
209
246
 
210
247
  /**
211
248
  * Overrides the inProgress field of the Inbox contract state
212
- * @param howMuch - How many blocks to move it forward
249
+ * @param howMuch - How many checkpoints to move it forward
213
250
  */
214
251
  public advanceInboxInProgress(howMuch: number | bigint): Promise<bigint> {
215
252
  return this.ethCheatCodes.execWithPausedAnvil(async () => {
@@ -248,6 +285,17 @@ export class RollupCheatCodes {
248
285
  });
249
286
  }
250
287
 
288
+ public insertOutbox(epoch: EpochNumber, numCheckpointsInEpoch: number, outHash: bigint) {
289
+ return this.ethCheatCodes.execWithPausedAnvil(async () => {
290
+ const outboxAddress = await this.rollup.read.getOutbox();
291
+ const epochRootSlot = OutboxContract.getEpochRootStorageSlot(epoch, numCheckpointsInEpoch);
292
+ await this.ethCheatCodes.store(EthAddress.fromString(outboxAddress), epochRootSlot, outHash);
293
+ this.logger.warn(
294
+ `Advanced outbox to epoch ${epoch} numCheckpointsInEpoch ${numCheckpointsInEpoch} with out hash ${outHash}`,
295
+ );
296
+ });
297
+ }
298
+
251
299
  /**
252
300
  * Executes an action impersonated as the owner of the Rollup contract.
253
301
  * @param action - The action to execute
@@ -293,7 +341,8 @@ export class RollupCheatCodes {
293
341
  }
294
342
 
295
343
  /**
296
- * Directly updates proving cost per mana.
344
+ * Directly updates proving cost per mana. Throws if the on-chain tx reverts
345
+ * (e.g. rate-limit cooldown, step cap, or floor) instead of silently succeeding.
297
346
  * @param ethValue - The new proving cost per mana in ETH
298
347
  */
299
348
  public async setProvingCostPerMana(ethValue: bigint) {
@@ -303,8 +352,37 @@ export class RollupCheatCodes {
303
352
  chain: this.client.chain,
304
353
  gasLimit: 1000000n,
305
354
  });
306
- await this.client.waitForTransactionReceipt({ hash });
355
+ const receipt = await this.client.waitForTransactionReceipt({ hash });
356
+ if (receipt.status !== 'success') {
357
+ throw new Error(
358
+ `setProvingCostPerMana(${ethValue}) reverted on L1 (tx ${hash}). ` +
359
+ `Likely FeeLib rate-limit (30-day cooldown or 1.5x step cap); ` +
360
+ `use clearProvingCostCooldown() between successive updates.`,
361
+ );
362
+ }
307
363
  this.logger.warn(`Updated proving cost per mana to ${ethValue}`);
308
364
  });
309
365
  }
366
+
367
+ /**
368
+ * Resets the 30-day proving-cost update cooldown enforced by FeeLib.updateProvingCostPerMana
369
+ * by zeroing `FeeStore.provingCostLastUpdate` directly in contract storage. Use between
370
+ * successive setProvingCostPerMana / bumpProvingCostPerMana calls so the later update can
371
+ * land instead of reverting. Does not touch L1 time, so PXE/tx-expiration state stays intact.
372
+ *
373
+ * @note This is tightly coupled to the `FeeStore` layout in
374
+ * l1-contracts/src/core/libraries/rollup/FeeLib.sol:
375
+ * slot + 0: CompressedFeeConfig config (uint256)
376
+ * slot + 1: L1GasOracleValues l1GasOracleValues (14+14+4 bytes, packed)
377
+ * slot + 2: uint64 provingCostLastUpdate (only member — zeroing the slot is safe)
378
+ * If the struct layout changes, update the offset below.
379
+ */
380
+ public async clearProvingCostCooldown() {
381
+ const feeStoreBaseSlot = hexToBigInt(keccak256(Buffer.from('aztec.fee.storage', 'utf-8')));
382
+ const provingCostLastUpdateSlot = feeStoreBaseSlot + 2n;
383
+ await this.ethCheatCodes.store(EthAddress.fromString(this.rollup.address), provingCostLastUpdateSlot, 0n, {
384
+ silent: true,
385
+ });
386
+ this.logger.warn(`Cleared proving-cost update cooldown`);
387
+ }
310
388
  }