@aztec/ethereum 0.72.1 → 0.74.0

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 (76) hide show
  1. package/dest/{ethereum_chain.d.ts → chain.d.ts} +1 -1
  2. package/dest/chain.d.ts.map +1 -0
  3. package/dest/{ethereum_chain.js → chain.js} +1 -1
  4. package/dest/client.d.ts +16 -0
  5. package/dest/client.d.ts.map +1 -0
  6. package/dest/client.js +35 -0
  7. package/dest/contracts/empire_base.d.ts +13 -0
  8. package/dest/contracts/empire_base.d.ts.map +1 -0
  9. package/dest/contracts/empire_base.js +10 -0
  10. package/dest/contracts/forwarder.d.ts +24 -0
  11. package/dest/contracts/forwarder.d.ts.map +1 -0
  12. package/dest/contracts/forwarder.js +81 -0
  13. package/dest/contracts/governance.d.ts +14 -0
  14. package/dest/contracts/governance.d.ts.map +1 -0
  15. package/dest/contracts/governance.js +31 -0
  16. package/dest/contracts/governance_proposer.d.ts +28 -0
  17. package/dest/contracts/governance_proposer.d.ts.map +1 -0
  18. package/dest/contracts/governance_proposer.js +71 -0
  19. package/dest/contracts/index.d.ts +5 -0
  20. package/dest/contracts/index.d.ts.map +1 -1
  21. package/dest/contracts/index.js +6 -1
  22. package/dest/contracts/rollup.d.ts +96 -5
  23. package/dest/contracts/rollup.d.ts.map +1 -1
  24. package/dest/contracts/rollup.js +188 -17
  25. package/dest/contracts/slashing_proposer.d.ts +21 -0
  26. package/dest/contracts/slashing_proposer.d.ts.map +1 -0
  27. package/dest/contracts/slashing_proposer.js +37 -0
  28. package/dest/deploy_l1_contracts.d.ts +2337 -1081
  29. package/dest/deploy_l1_contracts.d.ts.map +1 -1
  30. package/dest/deploy_l1_contracts.js +48 -22
  31. package/dest/index.d.ts +4 -1
  32. package/dest/index.d.ts.map +1 -1
  33. package/dest/index.js +5 -2
  34. package/dest/l1_reader.d.ts.map +1 -1
  35. package/dest/l1_reader.js +2 -3
  36. package/dest/l1_tx_utils.d.ts +80 -18
  37. package/dest/l1_tx_utils.d.ts.map +1 -1
  38. package/dest/l1_tx_utils.js +171 -20
  39. package/dest/l1_tx_utils_with_blobs.d.ts +12 -0
  40. package/dest/l1_tx_utils_with_blobs.d.ts.map +1 -0
  41. package/dest/l1_tx_utils_with_blobs.js +61 -0
  42. package/dest/queries.d.ts +15 -0
  43. package/dest/queries.d.ts.map +1 -0
  44. package/dest/queries.js +48 -0
  45. package/dest/test/delayed_tx_utils.d.ts +8 -0
  46. package/dest/test/delayed_tx_utils.d.ts.map +1 -0
  47. package/dest/test/delayed_tx_utils.js +21 -0
  48. package/dest/test/index.d.ts +2 -1
  49. package/dest/test/index.d.ts.map +1 -1
  50. package/dest/test/index.js +3 -2
  51. package/dest/types.d.ts +3 -1
  52. package/dest/types.d.ts.map +1 -1
  53. package/dest/utils.d.ts +1 -0
  54. package/dest/utils.d.ts.map +1 -1
  55. package/dest/utils.js +40 -4
  56. package/package.json +7 -4
  57. package/src/client.ts +56 -0
  58. package/src/contracts/empire_base.ts +19 -0
  59. package/src/contracts/forwarder.ts +136 -0
  60. package/src/contracts/governance.ts +50 -0
  61. package/src/contracts/governance_proposer.ts +91 -0
  62. package/src/contracts/index.ts +5 -0
  63. package/src/contracts/rollup.ts +277 -17
  64. package/src/contracts/slashing_proposer.ts +58 -0
  65. package/src/deploy_l1_contracts.ts +74 -26
  66. package/src/index.ts +4 -1
  67. package/src/l1_reader.ts +1 -2
  68. package/src/l1_tx_utils.ts +245 -35
  69. package/src/l1_tx_utils_with_blobs.ts +86 -0
  70. package/src/queries.ts +77 -0
  71. package/src/test/delayed_tx_utils.ts +24 -0
  72. package/src/test/index.ts +2 -1
  73. package/src/types.ts +4 -0
  74. package/src/utils.ts +44 -3
  75. package/dest/ethereum_chain.d.ts.map +0 -1
  76. /package/src/{ethereum_chain.ts → chain.ts} +0 -0
@@ -1,31 +1,89 @@
1
- import { AztecAddress } from '@aztec/foundation/aztec-address';
2
1
  import { memoize } from '@aztec/foundation/decorators';
3
- import { RollupAbi } from '@aztec/l1-artifacts';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+ import type { ViemSignature } from '@aztec/foundation/eth-signature';
4
+ import { RollupAbi, RollupStorage, SlasherAbi } from '@aztec/l1-artifacts';
4
5
 
5
6
  import {
7
+ type Account,
6
8
  type Chain,
7
9
  type GetContractReturnType,
8
10
  type Hex,
9
11
  type HttpTransport,
10
12
  type PublicClient,
11
13
  createPublicClient,
14
+ getAddress,
12
15
  getContract,
13
16
  http,
14
17
  } from 'viem';
15
18
 
19
+ import { createEthereumChain } from '../chain.js';
16
20
  import { type DeployL1Contracts } from '../deploy_l1_contracts.js';
17
- import { createEthereumChain } from '../ethereum_chain.js';
21
+ import { type L1ContractAddresses } from '../l1_contract_addresses.js';
18
22
  import { type L1ReaderConfig } from '../l1_reader.js';
23
+ import { formatViemError } from '../utils.js';
24
+ import { SlashingProposerContract } from './slashing_proposer.js';
25
+
26
+ export type L1RollupContractAddresses = Pick<
27
+ L1ContractAddresses,
28
+ | 'rollupAddress'
29
+ | 'inboxAddress'
30
+ | 'outboxAddress'
31
+ | 'feeJuicePortalAddress'
32
+ | 'feeJuiceAddress'
33
+ | 'stakingAssetAddress'
34
+ | 'rewardDistributorAddress'
35
+ >;
36
+
37
+ export type EpochProofQuoteViemArgs = {
38
+ epochToProve: bigint;
39
+ validUntilSlot: bigint;
40
+ bondAmount: bigint;
41
+ prover: `0x${string}`;
42
+ basisPointFee: number;
43
+ };
19
44
 
20
45
  export class RollupContract {
21
46
  private readonly rollup: GetContractReturnType<typeof RollupAbi, PublicClient<HttpTransport, Chain>>;
22
47
 
48
+ static get checkBlobStorageSlot(): bigint {
49
+ const asString = RollupStorage.find(storage => storage.label === 'checkBlob')?.slot;
50
+ if (asString === undefined) {
51
+ throw new Error('checkBlobStorageSlot not found');
52
+ }
53
+ return BigInt(asString);
54
+ }
55
+
56
+ static getFromL1ContractsValues(deployL1ContractsValues: DeployL1Contracts) {
57
+ const {
58
+ publicClient,
59
+ l1ContractAddresses: { rollupAddress },
60
+ } = deployL1ContractsValues;
61
+ return new RollupContract(publicClient, rollupAddress.toString());
62
+ }
63
+
64
+ static getFromConfig(config: L1ReaderConfig) {
65
+ const client = createPublicClient({
66
+ transport: http(config.l1RpcUrl),
67
+ chain: createEthereumChain(config.l1RpcUrl, config.l1ChainId).chainInfo,
68
+ });
69
+ const address = config.l1Contracts.rollupAddress.toString();
70
+ return new RollupContract(client, address);
71
+ }
72
+
23
73
  constructor(public readonly client: PublicClient<HttpTransport, Chain>, address: Hex) {
24
74
  this.rollup = getContract({ address, abi: RollupAbi, client });
25
75
  }
26
76
 
27
77
  public get address() {
28
- return AztecAddress.fromString(this.rollup.address);
78
+ return this.rollup.address;
79
+ }
80
+
81
+ @memoize
82
+ public async getSlashingProposer() {
83
+ const slasherAddress = await this.rollup.read.getSlasher();
84
+ const slasher = getContract({ address: slasherAddress, abi: SlasherAbi, client: this.client });
85
+ const proposerAddress = await slasher.read.PROPOSER();
86
+ return new SlashingProposerContract(this.client, proposerAddress);
29
87
  }
30
88
 
31
89
  @memoize
@@ -35,7 +93,42 @@ export class RollupContract {
35
93
 
36
94
  @memoize
37
95
  getL1GenesisTime() {
38
- return this.rollup.read.GENESIS_TIME();
96
+ return this.rollup.read.getGenesisTime();
97
+ }
98
+
99
+ @memoize
100
+ getClaimDurationInL2Slots() {
101
+ return this.rollup.read.CLAIM_DURATION_IN_L2_SLOTS();
102
+ }
103
+
104
+ @memoize
105
+ getEpochDuration() {
106
+ return this.rollup.read.getEpochDuration();
107
+ }
108
+
109
+ @memoize
110
+ getSlotDuration() {
111
+ return this.rollup.read.getSlotDuration();
112
+ }
113
+
114
+ @memoize
115
+ getTargetCommitteeSize() {
116
+ return this.rollup.read.TARGET_COMMITTEE_SIZE();
117
+ }
118
+
119
+ @memoize
120
+ getMinimumStake() {
121
+ return this.rollup.read.getMinimumStake();
122
+ }
123
+
124
+ public async getSlashingProposerAddress() {
125
+ const slasherAddress = await this.rollup.read.getSlasher();
126
+ const slasher = getContract({
127
+ address: getAddress(slasherAddress.toString()),
128
+ abi: SlasherAbi,
129
+ client: this.client,
130
+ });
131
+ return EthAddress.fromString(await slasher.read.PROPOSER());
39
132
  }
40
133
 
41
134
  getBlockNumber() {
@@ -70,25 +163,192 @@ export class RollupContract {
70
163
  return this.rollup.read.getCurrentProposer();
71
164
  }
72
165
 
166
+ getProposerAt(timestamp: bigint) {
167
+ return this.rollup.read.getProposerAt([timestamp]);
168
+ }
169
+
170
+ getBlock(blockNumber: bigint) {
171
+ return this.rollup.read.getBlock([blockNumber]);
172
+ }
173
+
174
+ getProofCommitmentEscrow() {
175
+ return this.rollup.read.PROOF_COMMITMENT_ESCROW();
176
+ }
177
+
178
+ getTips() {
179
+ return this.rollup.read.getTips();
180
+ }
181
+
182
+ getTimestampForSlot(slot: bigint) {
183
+ return this.rollup.read.getTimestampForSlot([slot]);
184
+ }
185
+
73
186
  async getEpochNumber(blockNumber?: bigint) {
74
187
  blockNumber ??= await this.getBlockNumber();
75
188
  return this.rollup.read.getEpochForBlock([BigInt(blockNumber)]);
76
189
  }
77
190
 
78
- static getFromL1ContractsValues(deployL1ContractsValues: DeployL1Contracts) {
191
+ async getRollupAddresses(): Promise<L1RollupContractAddresses> {
192
+ const [
193
+ inboxAddress,
194
+ outboxAddress,
195
+ feeJuicePortalAddress,
196
+ rewardDistributorAddress,
197
+ feeJuiceAddress,
198
+ stakingAssetAddress,
199
+ ] = (
200
+ await Promise.all([
201
+ this.rollup.read.INBOX(),
202
+ this.rollup.read.OUTBOX(),
203
+ this.rollup.read.FEE_JUICE_PORTAL(),
204
+ this.rollup.read.REWARD_DISTRIBUTOR(),
205
+ this.rollup.read.ASSET(),
206
+ this.rollup.read.getStakingAsset(),
207
+ ] as const)
208
+ ).map(EthAddress.fromString);
209
+
210
+ return {
211
+ rollupAddress: EthAddress.fromString(this.address),
212
+ inboxAddress,
213
+ outboxAddress,
214
+ feeJuicePortalAddress,
215
+ feeJuiceAddress,
216
+ stakingAssetAddress,
217
+ rewardDistributorAddress,
218
+ };
219
+ }
220
+
221
+ public async getEpochNumberForSlotNumber(slotNumber: bigint): Promise<bigint> {
222
+ return await this.rollup.read.getEpochAtSlot([slotNumber]);
223
+ }
224
+
225
+ getEpochProofPublicInputs(
226
+ args: readonly [
227
+ bigint,
228
+ readonly [
229
+ `0x${string}`,
230
+ `0x${string}`,
231
+ `0x${string}`,
232
+ `0x${string}`,
233
+ `0x${string}`,
234
+ `0x${string}`,
235
+ `0x${string}`,
236
+ ],
237
+ readonly `0x${string}`[],
238
+ `0x${string}`,
239
+ `0x${string}`,
240
+ ],
241
+ ) {
242
+ return this.rollup.read.getEpochProofPublicInputs(args);
243
+ }
244
+ public async getProofClaim() {
79
245
  const {
80
- publicClient,
81
- l1ContractAddresses: { rollupAddress },
82
- } = deployL1ContractsValues;
83
- return new RollupContract(publicClient, rollupAddress.toString());
246
+ epochToProve,
247
+ basisPointFee,
248
+ bondAmount,
249
+ bondProvider: bondProviderHex,
250
+ proposerClaimant: proposerClaimantHex,
251
+ } = await this.rollup.read.getProofClaim();
252
+
253
+ const bondProvider = EthAddress.fromString(bondProviderHex);
254
+ const proposerClaimant = EthAddress.fromString(proposerClaimantHex);
255
+
256
+ if (bondProvider.isZero() && proposerClaimant.isZero() && epochToProve === 0n) {
257
+ return undefined;
258
+ }
259
+
260
+ return {
261
+ epochToProve,
262
+ basisPointFee,
263
+ bondAmount,
264
+ bondProvider,
265
+ proposerClaimant,
266
+ };
84
267
  }
85
268
 
86
- static getFromConfig(config: L1ReaderConfig) {
87
- const client = createPublicClient({
88
- transport: http(config.l1RpcUrl),
89
- chain: createEthereumChain(config.l1RpcUrl, config.l1ChainId).chainInfo,
90
- });
91
- const address = config.l1Contracts.rollupAddress.toString();
92
- return new RollupContract(client, address);
269
+ async getClaimableEpoch(): Promise<bigint | undefined> {
270
+ try {
271
+ return await this.rollup.read.getClaimableEpoch();
272
+ } catch (err: unknown) {
273
+ throw formatViemError(err);
274
+ }
275
+ }
276
+
277
+ public async getEpochToProve(): Promise<bigint | undefined> {
278
+ try {
279
+ return await this.rollup.read.getEpochToProve();
280
+ } catch (err: unknown) {
281
+ throw formatViemError(err);
282
+ }
283
+ }
284
+
285
+ public async validateProofQuote(
286
+ quote: {
287
+ quote: EpochProofQuoteViemArgs;
288
+ signature: ViemSignature;
289
+ },
290
+ account: `0x${string}` | Account,
291
+ slotDuration: bigint | number,
292
+ ): Promise<void> {
293
+ if (typeof slotDuration === 'number') {
294
+ slotDuration = BigInt(slotDuration);
295
+ }
296
+ const timeOfNextL1Slot = BigInt((await this.client.getBlock()).timestamp + slotDuration);
297
+ const args = [timeOfNextL1Slot, quote] as const;
298
+ try {
299
+ await this.rollup.read.validateEpochProofRightClaimAtTime(args, { account });
300
+ } catch (err) {
301
+ throw formatViemError(err);
302
+ }
303
+ }
304
+
305
+ public async validateHeader(
306
+ args: readonly [
307
+ `0x${string}`,
308
+ ViemSignature[],
309
+ `0x${string}`,
310
+ bigint,
311
+ `0x${string}`,
312
+ {
313
+ ignoreDA: boolean;
314
+ ignoreSignatures: boolean;
315
+ },
316
+ ],
317
+ account: `0x${string}` | Account,
318
+ ): Promise<void> {
319
+ try {
320
+ await this.rollup.read.validateHeader(args, { account });
321
+ } catch (error: unknown) {
322
+ throw formatViemError(error);
323
+ }
324
+ }
325
+
326
+ /**
327
+ * @notice Calls `canProposeAtTime` with the time of the next Ethereum block and the sender address
328
+ *
329
+ * @dev Throws if unable to propose
330
+ *
331
+ * @param archive - The archive that we expect to be current state
332
+ * @return [slot, blockNumber] - If you can propose, the L2 slot number and L2 block number of the next Ethereum block,
333
+ * @throws otherwise
334
+ */
335
+ public async canProposeAtNextEthBlock(
336
+ archive: Buffer,
337
+ account: `0x${string}` | Account,
338
+ slotDuration: bigint | number,
339
+ ): Promise<[bigint, bigint]> {
340
+ if (typeof slotDuration === 'number') {
341
+ slotDuration = BigInt(slotDuration);
342
+ }
343
+ const timeOfNextL1Slot = (await this.client.getBlock()).timestamp + slotDuration;
344
+ try {
345
+ const [slot, blockNumber] = await this.rollup.read.canProposeAtTime(
346
+ [timeOfNextL1Slot, `0x${archive.toString('hex')}`],
347
+ { account },
348
+ );
349
+ return [slot, blockNumber];
350
+ } catch (err: unknown) {
351
+ throw formatViemError(err);
352
+ }
93
353
  }
94
354
  }
@@ -0,0 +1,58 @@
1
+ import { EthAddress } from '@aztec/foundation/eth-address';
2
+ import { SlashingProposerAbi } from '@aztec/l1-artifacts';
3
+
4
+ import {
5
+ type Chain,
6
+ type GetContractReturnType,
7
+ type Hex,
8
+ type HttpTransport,
9
+ type PublicClient,
10
+ getContract,
11
+ } from 'viem';
12
+
13
+ import type { L1Clients } from '../deploy_l1_contracts.js';
14
+ import type { L1TxRequest } from '../l1_tx_utils.js';
15
+ import { type IEmpireBase, encodeVote } from './empire_base.js';
16
+
17
+ export class SlashingProposerContract implements IEmpireBase {
18
+ private readonly proposer: GetContractReturnType<typeof SlashingProposerAbi, PublicClient<HttpTransport, Chain>>;
19
+
20
+ constructor(public readonly client: L1Clients['publicClient'], address: Hex) {
21
+ this.proposer = getContract({ address, abi: SlashingProposerAbi, client });
22
+ }
23
+
24
+ public get address() {
25
+ return EthAddress.fromString(this.proposer.address);
26
+ }
27
+
28
+ public getQuorumSize() {
29
+ return this.proposer.read.N();
30
+ }
31
+
32
+ public getRoundSize() {
33
+ return this.proposer.read.M();
34
+ }
35
+
36
+ public computeRound(slot: bigint): Promise<bigint> {
37
+ return this.proposer.read.computeRound([slot]);
38
+ }
39
+
40
+ public async getRoundInfo(
41
+ rollupAddress: Hex,
42
+ round: bigint,
43
+ ): Promise<{ lastVote: bigint; leader: Hex; executed: boolean }> {
44
+ const roundInfo = await this.proposer.read.rounds([rollupAddress, round]);
45
+ return {
46
+ lastVote: roundInfo[0],
47
+ leader: roundInfo[1],
48
+ executed: roundInfo[2],
49
+ };
50
+ }
51
+
52
+ public createVoteRequest(payload: Hex): L1TxRequest {
53
+ return {
54
+ to: this.address.toString(),
55
+ data: encodeVote(payload),
56
+ };
57
+ }
58
+ }
@@ -9,14 +9,14 @@ import {
9
9
  ExtRollupLibBytecode,
10
10
  FeeJuicePortalAbi,
11
11
  FeeJuicePortalBytecode,
12
+ ForwarderAbi,
13
+ ForwarderBytecode,
12
14
  GovernanceAbi,
13
15
  GovernanceBytecode,
14
16
  GovernanceProposerAbi,
15
17
  GovernanceProposerBytecode,
16
18
  InboxAbi,
17
19
  InboxBytecode,
18
- LeonidasLibAbi,
19
- LeonidasLibBytecode,
20
20
  OutboxAbi,
21
21
  OutboxBytecode,
22
22
  RegistryAbi,
@@ -28,18 +28,27 @@ import {
28
28
  RollupLinkReferences,
29
29
  SlashFactoryAbi,
30
30
  SlashFactoryBytecode,
31
+ StakingLibAbi,
32
+ StakingLibBytecode,
31
33
  TestERC20Abi,
32
34
  TestERC20Bytecode,
35
+ ValidatorSelectionLibAbi,
36
+ ValidatorSelectionLibBytecode,
33
37
  } from '@aztec/l1-artifacts';
34
38
 
35
39
  import type { Abi, Narrow } from 'abitype';
36
40
  import {
37
41
  type Account,
38
42
  type Chain,
43
+ type Client,
39
44
  type Hex,
40
45
  type HttpTransport,
46
+ type PublicActions,
41
47
  type PublicClient,
48
+ type PublicRpcSchema,
49
+ type WalletActions,
42
50
  type WalletClient,
51
+ type WalletRpcSchema,
43
52
  concatHex,
44
53
  createPublicClient,
45
54
  createWalletClient,
@@ -50,15 +59,18 @@ import {
50
59
  http,
51
60
  numberToHex,
52
61
  padHex,
62
+ publicActions,
53
63
  } from 'viem';
54
64
  import { type HDAccount, type PrivateKeyAccount, mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
55
65
  import { foundry } from 'viem/chains';
56
66
 
67
+ import { isAnvilTestChain } from './chain.js';
57
68
  import { type L1ContractsConfig } from './config.js';
58
- import { isAnvilTestChain } from './ethereum_chain.js';
59
69
  import { type L1ContractAddresses } from './l1_contract_addresses.js';
60
70
  import { L1TxUtils } from './l1_tx_utils.js';
61
71
 
72
+ export const DEPLOYER_ADDRESS: Hex = '0x4e59b44847b379578588920cA78FbF26c0B4956C';
73
+
62
74
  /**
63
75
  * Return type of the deployL1Contract function.
64
76
  */
@@ -128,14 +140,18 @@ export const l1Artifacts = {
128
140
  libraries: {
129
141
  linkReferences: RollupLinkReferences,
130
142
  libraryCode: {
131
- LeonidasLib: {
132
- contractAbi: LeonidasLibAbi,
133
- contractBytecode: LeonidasLibBytecode as Hex,
143
+ ValidatorSelectionLib: {
144
+ contractAbi: ValidatorSelectionLibAbi,
145
+ contractBytecode: ValidatorSelectionLibBytecode as Hex,
134
146
  },
135
147
  ExtRollupLib: {
136
148
  contractAbi: ExtRollupLibAbi,
137
149
  contractBytecode: ExtRollupLibBytecode as Hex,
138
150
  },
151
+ StakingLib: {
152
+ contractAbi: StakingLibAbi,
153
+ contractBytecode: StakingLibBytecode as Hex,
154
+ },
139
155
  },
140
156
  },
141
157
  },
@@ -190,7 +206,13 @@ export interface DeployL1ContractsArgs extends L1ContractsConfig {
190
206
 
191
207
  export type L1Clients = {
192
208
  publicClient: PublicClient<HttpTransport, Chain>;
193
- walletClient: WalletClient<HttpTransport, Chain, Account>;
209
+ walletClient: Client<
210
+ HttpTransport,
211
+ Chain,
212
+ PrivateKeyAccount,
213
+ [...WalletRpcSchema, ...PublicRpcSchema],
214
+ PublicActions<HttpTransport, Chain> & WalletActions<Chain, PrivateKeyAccount>
215
+ >;
194
216
  };
195
217
 
196
218
  /**
@@ -212,18 +234,25 @@ export function createL1Clients(
212
234
  : mnemonicToAccount(mnemonicOrPrivateKeyOrHdAccount)
213
235
  : mnemonicOrPrivateKeyOrHdAccount;
214
236
 
237
+ // From what I can see, this is the difference between the HDAccount and the PrivateKeyAccount
238
+ // and we don't need it for anything. This lets us use the same type for both.
239
+ // eslint-disable-next-line camelcase
240
+ hdAccount.experimental_signAuthorization ??= () => {
241
+ throw new Error('experimental_signAuthorization not implemented for HDAccount');
242
+ };
243
+
215
244
  const walletClient = createWalletClient({
216
245
  account: hdAccount,
217
246
  chain,
218
247
  transport: http(rpcUrl),
219
- });
248
+ }).extend(publicActions);
220
249
  const publicClient = createPublicClient({
221
250
  chain,
222
251
  transport: http(rpcUrl),
223
252
  pollingInterval: 100,
224
253
  });
225
254
 
226
- return { walletClient, publicClient };
255
+ return { walletClient, publicClient } as L1Clients;
227
256
  }
228
257
 
229
258
  /**
@@ -414,18 +443,18 @@ export const deployL1Contracts = async (
414
443
  ].map(txHash => publicClient.waitForTransactionReceipt({ hash: txHash })),
415
444
  );
416
445
 
417
- const initiateValidatorSetTxHash = await rollup.write.cheat__InitialiseValidatorSet([
418
- newValidatorsAddresses.map(v => ({
419
- attester: v,
420
- proposer: v,
421
- withdrawer: v,
422
- amount: args.minimumStake,
423
- })),
424
- ]);
446
+ const validators = newValidatorsAddresses.map(v => ({
447
+ attester: v,
448
+ proposer: getExpectedAddress(ForwarderAbi, ForwarderBytecode, [v], v).address,
449
+ withdrawer: v,
450
+ amount: args.minimumStake,
451
+ }));
452
+ const initiateValidatorSetTxHash = await rollup.write.cheat__InitialiseValidatorSet([validators]);
425
453
  txHashes.push(initiateValidatorSetTxHash);
426
- logger.info(
427
- `Initialized validator set (${newValidatorsAddresses.join(', ')}) in tx ${initiateValidatorSetTxHash}`,
428
- );
454
+ logger.info(`Initialized validator set`, {
455
+ validators,
456
+ txHash: initiateValidatorSetTxHash,
457
+ });
429
458
  }
430
459
  }
431
460
 
@@ -663,15 +692,12 @@ export async function deployL1Contract(
663
692
  }
664
693
 
665
694
  if (maybeSalt) {
666
- const salt = padHex(maybeSalt, { size: 32 });
667
- const deployer: Hex = '0x4e59b44847b379578588920cA78FbF26c0B4956C';
668
- const calldata = encodeDeployData({ abi, bytecode, args });
669
- resultingAddress = getContractAddress({ from: deployer, salt, bytecode: calldata, opcode: 'CREATE2' });
695
+ const { address, paddedSalt: salt, calldata } = getExpectedAddress(abi, bytecode, args, maybeSalt);
696
+ resultingAddress = address;
670
697
  const existing = await publicClient.getBytecode({ address: resultingAddress });
671
-
672
698
  if (existing === undefined || existing === '0x') {
673
699
  const res = await l1TxUtils.sendTransaction({
674
- to: deployer,
700
+ to: DEPLOYER_ADDRESS,
675
701
  data: concatHex([salt, calldata]),
676
702
  });
677
703
  txHash = res.txHash;
@@ -701,4 +727,26 @@ export async function deployL1Contract(
701
727
 
702
728
  return { address: EthAddress.fromString(resultingAddress!), txHash };
703
729
  }
730
+
731
+ export function getExpectedAddress(
732
+ abi: Narrow<Abi | readonly unknown[]>,
733
+ bytecode: Hex,
734
+ args: readonly unknown[],
735
+ salt: Hex,
736
+ ) {
737
+ const paddedSalt = padHex(salt, { size: 32 });
738
+ const calldata = encodeDeployData({ abi, bytecode, args });
739
+ const address = getContractAddress({
740
+ from: DEPLOYER_ADDRESS,
741
+ salt: paddedSalt,
742
+ bytecode: calldata,
743
+ opcode: 'CREATE2',
744
+ });
745
+ return {
746
+ address,
747
+ paddedSalt,
748
+ calldata,
749
+ };
750
+ }
751
+
704
752
  // docs:end:deployL1Contract
package/src/index.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  export * from './constants.js';
2
2
  export * from './deploy_l1_contracts.js';
3
- export * from './ethereum_chain.js';
3
+ export * from './chain.js';
4
4
  export * from './eth_cheat_codes.js';
5
5
  export * from './l1_tx_utils.js';
6
+ export * from './l1_tx_utils_with_blobs.js';
6
7
  export * from './l1_contract_addresses.js';
7
8
  export * from './l1_reader.js';
8
9
  export * from './utils.js';
9
10
  export * from './config.js';
10
11
  export * from './types.js';
11
12
  export * from './contracts/index.js';
13
+ export * from './queries.js';
14
+ export * from './client.js';
package/src/l1_reader.ts CHANGED
@@ -25,10 +25,9 @@ export const l1ReaderConfigMappings: ConfigMappingsType<L1ReaderConfig> = {
25
25
  defaultValue: 31337,
26
26
  description: 'The chain ID of the ethereum host.',
27
27
  },
28
- // NOTE: Special case for l1Contracts
29
28
  l1Contracts: {
30
29
  description: 'The deployed L1 contract addresses',
31
- defaultValue: l1ContractAddressesMapping,
30
+ nested: l1ContractAddressesMapping,
32
31
  },
33
32
  viemPollingIntervalMS: {
34
33
  env: 'L1_READER_VIEM_POLLING_INTERVAL_MS',