@aztec/ethereum 0.0.1-commit.f2ce05ee → 0.0.1-commit.f5a9928
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/client.d.ts +27 -3
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +63 -8
- package/dest/config.d.ts +17 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +38 -10
- package/dest/contracts/chain_state_override.d.ts +78 -0
- package/dest/contracts/chain_state_override.d.ts.map +1 -0
- package/dest/contracts/chain_state_override.js +137 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts +105 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
- package/dest/contracts/fee_asset_price_oracle.js +656 -0
- package/dest/contracts/governance.d.ts +135 -35
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +229 -18
- package/dest/contracts/governance_proposer.d.ts +33 -2
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +54 -6
- package/dest/contracts/gse.d.ts +4 -2
- package/dest/contracts/gse.d.ts.map +1 -1
- package/dest/contracts/gse.js +2 -2
- package/dest/contracts/inbox.d.ts +3 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +12 -7
- package/dest/contracts/index.d.ts +4 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +3 -2
- package/dest/contracts/multicall.d.ts +127 -12
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +201 -94
- package/dest/contracts/outbox.d.ts +27 -4
- package/dest/contracts/outbox.d.ts.map +1 -1
- package/dest/contracts/outbox.js +34 -7
- package/dest/contracts/registry.d.ts +3 -1
- package/dest/contracts/registry.d.ts.map +1 -1
- package/dest/contracts/registry.js +30 -1
- package/dest/contracts/rollup.d.ts +5437 -34
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +448 -104
- package/dest/contracts/slashing_proposer.d.ts +171 -0
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/slashing_proposer.js +753 -0
- package/dest/contracts/watch_event.d.ts +36 -0
- package/dest/contracts/watch_event.d.ts.map +1 -0
- package/dest/contracts/watch_event.js +66 -0
- package/dest/deploy_aztec_l1_contracts.d.ts +5 -9
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +48 -27
- package/dest/deploy_l1_contract.js +3 -3
- package/dest/foundry_binary.d.ts +13 -0
- package/dest/foundry_binary.d.ts.map +1 -0
- package/dest/foundry_binary.js +52 -0
- package/dest/generated/l1-contracts-defaults.d.ts +3 -3
- package/dest/generated/l1-contracts-defaults.js +3 -3
- package/dest/l1_artifacts.d.ts +15524 -15847
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +9 -24
- package/dest/l1_contract_addresses.d.ts +61 -65
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +101 -82
- package/dest/l1_reader.d.ts +5 -5
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +9 -7
- package/dest/l1_tx_utils/config.d.ts +7 -1
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +17 -4
- package/dest/l1_tx_utils/factory.d.ts +18 -10
- package/dest/l1_tx_utils/factory.d.ts.map +1 -1
- package/dest/l1_tx_utils/factory.js +17 -7
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +1 -1
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +1 -1
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +15 -15
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +9 -15
- package/dest/l1_tx_utils/index-blobs.d.ts +3 -3
- package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -1
- package/dest/l1_tx_utils/index-blobs.js +2 -2
- package/dest/l1_tx_utils/index.d.ts +2 -1
- package/dest/l1_tx_utils/index.d.ts.map +1 -1
- package/dest/l1_tx_utils/index.js +1 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +26 -7
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +156 -79
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +57 -23
- package/dest/l1_tx_utils/tx_delayer.d.ts +58 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
- package/dest/{test → l1_tx_utils}/tx_delayer.js +67 -37
- package/dest/publisher_manager.d.ts +34 -8
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +119 -8
- package/dest/queries.d.ts +13 -2
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +62 -3
- package/dest/test/blob_kzg_warmup.d.ts +19 -0
- package/dest/test/blob_kzg_warmup.d.ts.map +1 -0
- package/dest/test/blob_kzg_warmup.js +64 -0
- package/dest/test/chain_monitor.d.ts +55 -4
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +104 -3
- package/dest/test/eth_cheat_codes.d.ts +31 -6
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +67 -44
- package/dest/test/index.d.ts +2 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +1 -2
- package/dest/test/recording_rpc_server.d.ts +18 -0
- package/dest/test/recording_rpc_server.d.ts.map +1 -0
- package/dest/test/recording_rpc_server.js +68 -0
- package/dest/test/rollup_cheat_codes.d.ts +60 -3
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +86 -7
- package/dest/test/start_anvil.d.ts +23 -3
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +182 -32
- package/dest/test/upgrade_utils.js +2 -2
- package/dest/utils.d.ts +9 -2
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +59 -24
- package/package.json +6 -8
- package/src/client.ts +72 -2
- package/src/config.ts +58 -14
- package/src/contracts/chain_state_override.ts +200 -0
- package/src/contracts/fee_asset_price_oracle.ts +285 -0
- package/src/contracts/governance.ts +313 -13
- package/src/contracts/governance_proposer.ts +58 -9
- package/src/contracts/gse.ts +7 -2
- package/src/contracts/inbox.ts +13 -5
- package/src/contracts/index.ts +3 -2
- package/src/contracts/multicall.ts +243 -105
- package/src/contracts/outbox.ts +42 -8
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +507 -109
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +119 -45
- package/src/contracts/watch_event.ts +110 -0
- package/src/deploy_aztec_l1_contracts.ts +75 -39
- package/src/deploy_l1_contract.ts +3 -3
- package/src/foundry_binary.ts +57 -0
- package/src/generated/l1-contracts-defaults.ts +3 -3
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +120 -94
- package/src/l1_reader.ts +17 -10
- package/src/l1_tx_utils/config.ts +23 -3
- package/src/l1_tx_utils/factory.ts +31 -31
- package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +1 -1
- package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +1 -1
- package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +43 -54
- package/src/l1_tx_utils/index-blobs.ts +2 -2
- package/src/l1_tx_utils/index.ts +1 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +149 -64
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +57 -17
- package/src/{test → l1_tx_utils}/tx_delayer.ts +93 -56
- package/src/publisher_manager.ts +143 -12
- package/src/queries.ts +70 -4
- package/src/test/blob_kzg_warmup.ts +65 -0
- package/src/test/chain_monitor.ts +148 -3
- package/src/test/eth_cheat_codes.ts +63 -47
- package/src/test/index.ts +1 -2
- package/src/test/recording_rpc_server.ts +69 -0
- package/src/test/rollup_cheat_codes.ts +115 -6
- package/src/test/start_anvil.ts +212 -32
- package/src/test/upgrade_utils.ts +2 -2
- package/src/utils.ts +56 -29
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -67
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -207
- package/dest/contracts/tally_slashing_proposer.d.ts +0 -140
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/tally_slashing_proposer.js +0 -320
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +0 -26
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +0 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +0 -26
- package/dest/test/delayed_tx_utils.d.ts +0 -13
- package/dest/test/delayed_tx_utils.d.ts.map +0 -1
- package/dest/test/delayed_tx_utils.js +0 -28
- package/dest/test/tx_delayer.d.ts +0 -36
- package/dest/test/tx_delayer.d.ts.map +0 -1
- package/src/contracts/empire_slashing_proposer.ts +0 -259
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
- package/src/test/delayed_tx_utils.ts +0 -52
|
@@ -3,11 +3,13 @@ import type { ViemClient } from '@aztec/ethereum/types';
|
|
|
3
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
|
+
import { memoize } from '@aztec/foundation/decorators';
|
|
6
7
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
7
8
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
9
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
8
10
|
import { hexToBuffer } from '@aztec/foundation/string';
|
|
9
11
|
import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
|
|
10
|
-
import {
|
|
12
|
+
import { SlashingProposerAbi } from '@aztec/l1-artifacts/SlashingProposerAbi';
|
|
11
13
|
|
|
12
14
|
import {
|
|
13
15
|
type GetContractReturnType,
|
|
@@ -18,14 +20,23 @@ import {
|
|
|
18
20
|
getContract,
|
|
19
21
|
} from 'viem';
|
|
20
22
|
|
|
23
|
+
import { type WatchContractEventOptions, watchContractEvent } from './watch_event.js';
|
|
24
|
+
|
|
21
25
|
/**
|
|
22
|
-
* Wrapper around the
|
|
26
|
+
* Wrapper around the SlashingProposer contract that provides
|
|
23
27
|
* a TypeScript interface for interacting with the consensus-based slashing system.
|
|
24
28
|
*/
|
|
25
|
-
export class
|
|
26
|
-
private readonly contract: GetContractReturnType<typeof
|
|
29
|
+
export class SlashingProposerContract {
|
|
30
|
+
private readonly contract: GetContractReturnType<typeof SlashingProposerAbi, ViemClient>;
|
|
31
|
+
private readonly logger = createLogger('ethereum:slashing_proposer');
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Slash target validators of the last round asked for. Safe to cache because a round's targets are the committees
|
|
35
|
+
* of epochs that had already ended when the round opened (see SLASH_OFFSET_IN_ROUNDS), and those committees are
|
|
36
|
+
* sampled from validator set and randao snapshots taken before the epoch started, so they cannot change while the
|
|
37
|
+
* round is live. The promise is cached rather than the result, so concurrent callers share one in-flight read.
|
|
38
|
+
*/
|
|
39
|
+
private slashTargetValidators: { round: bigint; validators: Promise<EthAddress[]> } | undefined;
|
|
29
40
|
|
|
30
41
|
constructor(
|
|
31
42
|
public readonly client: ViemClient,
|
|
@@ -33,7 +44,7 @@ export class TallySlashingProposerContract {
|
|
|
33
44
|
) {
|
|
34
45
|
this.contract = getContract({
|
|
35
46
|
address: typeof address === 'string' ? address : address.toString(),
|
|
36
|
-
abi:
|
|
47
|
+
abi: SlashingProposerAbi,
|
|
37
48
|
client,
|
|
38
49
|
});
|
|
39
50
|
}
|
|
@@ -66,6 +77,8 @@ export class TallySlashingProposerContract {
|
|
|
66
77
|
return this.contract.read.EXECUTION_DELAY_IN_ROUNDS();
|
|
67
78
|
}
|
|
68
79
|
|
|
80
|
+
/** Returns the slash amounts for the three slash unit levels. Immutable on the contract, so memoized. */
|
|
81
|
+
@memoize
|
|
69
82
|
public getSlashingAmounts(): Promise<[bigint, bigint, bigint]> {
|
|
70
83
|
return Promise.all([
|
|
71
84
|
this.contract.read.SLASH_AMOUNT_SMALL(),
|
|
@@ -136,12 +149,12 @@ export class TallySlashingProposerContract {
|
|
|
136
149
|
|
|
137
150
|
/** Tries to extract a VoteCast event from the given logs. */
|
|
138
151
|
public tryExtractVoteCastEvent(logs: Log[]) {
|
|
139
|
-
return tryExtractEvent(logs, this.address.toString(),
|
|
152
|
+
return tryExtractEvent(logs, this.address.toString(), SlashingProposerAbi, 'VoteCast');
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
/** Tries to extract a RoundExecuted event from the given logs. */
|
|
143
156
|
public tryExtractRoundExecutedEvent(logs: Log[]) {
|
|
144
|
-
return tryExtractEvent(logs, this.address.toString(),
|
|
157
|
+
return tryExtractEvent(logs, this.address.toString(), SlashingProposerAbi, 'RoundExecuted');
|
|
145
158
|
}
|
|
146
159
|
|
|
147
160
|
/**
|
|
@@ -161,9 +174,9 @@ export class TallySlashingProposerContract {
|
|
|
161
174
|
|
|
162
175
|
return {
|
|
163
176
|
to: this.contract.address,
|
|
164
|
-
abi:
|
|
177
|
+
abi: SlashingProposerAbi,
|
|
165
178
|
data: encodeFunctionData({
|
|
166
|
-
abi:
|
|
179
|
+
abi: SlashingProposerAbi,
|
|
167
180
|
functionName: 'vote',
|
|
168
181
|
args: [votes, signature.toViemSignature()],
|
|
169
182
|
}),
|
|
@@ -173,7 +186,7 @@ export class TallySlashingProposerContract {
|
|
|
173
186
|
/** Returns the typed data definition to EIP712-sign for voting */
|
|
174
187
|
public buildVoteTypedData(votes: Hex, slot: SlotNumber): TypedDataDefinition {
|
|
175
188
|
const domain = {
|
|
176
|
-
name: '
|
|
189
|
+
name: 'SlashingProposer',
|
|
177
190
|
version: '1',
|
|
178
191
|
chainId: this.client.chain.id,
|
|
179
192
|
verifyingContract: this.contract.address,
|
|
@@ -209,9 +222,9 @@ export class TallySlashingProposerContract {
|
|
|
209
222
|
public buildVoteRequestWithSignature(votes: Hex, signature: { v: number; r: Hex; s: Hex }): L1TxRequest {
|
|
210
223
|
return {
|
|
211
224
|
to: this.contract.address,
|
|
212
|
-
abi:
|
|
225
|
+
abi: SlashingProposerAbi,
|
|
213
226
|
data: encodeFunctionData({
|
|
214
|
-
abi:
|
|
227
|
+
abi: SlashingProposerAbi,
|
|
215
228
|
functionName: 'vote',
|
|
216
229
|
args: [votes, signature],
|
|
217
230
|
}),
|
|
@@ -227,75 +240,136 @@ export class TallySlashingProposerContract {
|
|
|
227
240
|
public buildExecuteRoundRequest(round: bigint, committees: EthAddress[][]): L1TxRequest {
|
|
228
241
|
return {
|
|
229
242
|
to: this.contract.address,
|
|
230
|
-
abi: mergeAbis([
|
|
243
|
+
abi: mergeAbis([SlashingProposerAbi, SlasherAbi]),
|
|
231
244
|
data: encodeFunctionData({
|
|
232
|
-
abi:
|
|
245
|
+
abi: SlashingProposerAbi,
|
|
233
246
|
functionName: 'executeRound',
|
|
234
247
|
args: [round, committees.map(c => c.map(addr => addr.toString()))],
|
|
235
248
|
}),
|
|
236
249
|
};
|
|
237
250
|
}
|
|
238
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Returns the validators eligible to be voted against in a round, in the order votes encode them. Cached for the
|
|
254
|
+
* last round asked for: reading them runs a committee sampling simulation on L1, and every vote of a round decodes
|
|
255
|
+
* against the same list, so a caller walking a round's votes would otherwise repeat that call per vote. Only the
|
|
256
|
+
* last round is kept since callers move forward round by round.
|
|
257
|
+
*/
|
|
258
|
+
public getSlashTargetValidators(round: bigint): Promise<EthAddress[]> {
|
|
259
|
+
const cached = this.slashTargetValidators;
|
|
260
|
+
if (cached?.round === round) {
|
|
261
|
+
return cached.validators;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const entry = { round, validators: this.fetchSlashTargetValidators(round) };
|
|
265
|
+
this.slashTargetValidators = entry;
|
|
266
|
+
// A failed read must not stay cached, or every later vote of the round would replay the same rejection
|
|
267
|
+
entry.validators.catch(() => {
|
|
268
|
+
if (this.slashTargetValidators === entry) {
|
|
269
|
+
this.slashTargetValidators = undefined;
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
return entry.validators;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
private async fetchSlashTargetValidators(round: bigint): Promise<EthAddress[]> {
|
|
276
|
+
const { result } = await this.contract.simulate.getSlashTargetCommittees([round]);
|
|
277
|
+
return result.flat().map(validator => EthAddress.fromString(validator));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Returns the slash amount voted for each target validator by a single vote of a round.
|
|
282
|
+
* @param index - Position of the vote within the round, from 0 (inclusive) to the round's vote count (exclusive)
|
|
283
|
+
*/
|
|
284
|
+
public async getVoteAt(round: bigint, index: bigint): Promise<SlashVoteTarget[]> {
|
|
285
|
+
const [validators, vote, slashAmounts] = await Promise.all([
|
|
286
|
+
this.getSlashTargetValidators(round),
|
|
287
|
+
this.contract.read.getVotes([round, index]),
|
|
288
|
+
this.getSlashingAmounts(),
|
|
289
|
+
]);
|
|
290
|
+
return decodeVote(vote, validators, slashAmounts);
|
|
291
|
+
}
|
|
292
|
+
|
|
239
293
|
/** Returns the last vote emitted for a given round */
|
|
240
294
|
public async getLastVote(round: bigint) {
|
|
241
295
|
const { voteCount } = await this.getRound(round);
|
|
242
|
-
|
|
243
|
-
const vote = await this.contract.read.getVotes([round, voteCount - 1n]);
|
|
244
|
-
const decoded = decodeSlashConsensusVotes(hexToBuffer(vote));
|
|
245
|
-
const slashAmounts = await this.getSlashingAmounts();
|
|
246
|
-
return decoded
|
|
247
|
-
.map((units, i) => ({
|
|
248
|
-
validator: EthAddress.fromString(validators[i]),
|
|
249
|
-
slashAmount: slashAmounts[units - 1] ?? 0n,
|
|
250
|
-
}))
|
|
251
|
-
.filter(v => v.slashAmount > 0n);
|
|
296
|
+
return await this.getVoteAt(round, voteCount - 1n);
|
|
252
297
|
}
|
|
253
298
|
|
|
254
299
|
/**
|
|
255
|
-
* Listen for VoteCast events
|
|
300
|
+
* Listen for VoteCast events. Events are delivered by polling `eth_getLogs`: a reorg may re-emit them and
|
|
301
|
+
* removals are never reported, and events mined within roughly one polling interval of subscribing may be missed.
|
|
256
302
|
* @param callback - Callback function to handle vote cast events
|
|
257
303
|
* @returns Unwatch function
|
|
258
304
|
*/
|
|
259
|
-
public listenToVoteCast(
|
|
260
|
-
|
|
261
|
-
|
|
305
|
+
public listenToVoteCast(
|
|
306
|
+
callback: (args: { round: bigint; proposer: string }) => unknown,
|
|
307
|
+
options?: WatchContractEventOptions,
|
|
308
|
+
): () => void {
|
|
309
|
+
return watchContractEvent(
|
|
310
|
+
this.client,
|
|
311
|
+
this.logger,
|
|
262
312
|
{
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
313
|
+
address: this.contract.address,
|
|
314
|
+
abi: SlashingProposerAbi,
|
|
315
|
+
eventName: 'VoteCast',
|
|
316
|
+
onLog: log => {
|
|
317
|
+
const { round, proposer } = log.args;
|
|
318
|
+
if (round !== undefined && proposer) {
|
|
319
|
+
return callback({ round, proposer });
|
|
269
320
|
}
|
|
270
321
|
},
|
|
271
322
|
},
|
|
323
|
+
options,
|
|
272
324
|
);
|
|
273
325
|
}
|
|
274
326
|
|
|
275
327
|
/**
|
|
276
|
-
* Listen for RoundExecuted events
|
|
328
|
+
* Listen for RoundExecuted events. Events are delivered by polling `eth_getLogs`: a reorg may re-emit them and
|
|
329
|
+
* removals are never reported, and events mined within roughly one polling interval of subscribing may be missed.
|
|
277
330
|
* @param callback - Callback function to handle round executed events
|
|
278
331
|
* @returns Unwatch function
|
|
279
332
|
*/
|
|
280
333
|
public listenToRoundExecuted(
|
|
281
|
-
callback: (args: { round: bigint; slashCount: bigint; l1BlockHash: Hex }) =>
|
|
334
|
+
callback: (args: { round: bigint; slashCount: bigint; l1BlockHash: Hex }) => unknown,
|
|
335
|
+
options?: WatchContractEventOptions,
|
|
282
336
|
): () => void {
|
|
283
|
-
return
|
|
284
|
-
|
|
337
|
+
return watchContractEvent(
|
|
338
|
+
this.client,
|
|
339
|
+
this.logger,
|
|
285
340
|
{
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
341
|
+
address: this.contract.address,
|
|
342
|
+
abi: SlashingProposerAbi,
|
|
343
|
+
eventName: 'RoundExecuted',
|
|
344
|
+
onLog: log => {
|
|
345
|
+
const { round, slashCount } = log.args;
|
|
346
|
+
if (round !== undefined && slashCount !== undefined) {
|
|
347
|
+
return callback({ round, slashCount, l1BlockHash: log.blockHash });
|
|
292
348
|
}
|
|
293
349
|
},
|
|
294
350
|
},
|
|
351
|
+
options,
|
|
295
352
|
);
|
|
296
353
|
}
|
|
297
354
|
}
|
|
298
355
|
|
|
356
|
+
/**
|
|
357
|
+
* A validator targeted by a slashing vote, with the amount voted. The position is the validator's index in the
|
|
358
|
+
* round's flattened slash target committees — the unit the contract tallies quorum by. A validator sitting in
|
|
359
|
+
* several of the round's committees holds several positions, each with its own tally.
|
|
360
|
+
*/
|
|
361
|
+
export type SlashVoteTarget = { validator: EthAddress; slashAmount: bigint; position: number };
|
|
362
|
+
|
|
363
|
+
function decodeVote(vote: Hex, validators: EthAddress[], slashAmounts: [bigint, bigint, bigint]): SlashVoteTarget[] {
|
|
364
|
+
return decodeSlashConsensusVotes(hexToBuffer(vote))
|
|
365
|
+
.map((units, position) => ({
|
|
366
|
+
validator: validators[position],
|
|
367
|
+
slashAmount: slashAmounts[units - 1] ?? 0n,
|
|
368
|
+
position,
|
|
369
|
+
}))
|
|
370
|
+
.filter(v => v.slashAmount > 0n);
|
|
371
|
+
}
|
|
372
|
+
|
|
299
373
|
/**
|
|
300
374
|
* Decodes a Buffer containing slash votes back into an array of numbers.
|
|
301
375
|
* Each vote is represented as a 2-bit value (0, 1, 2, or 3) representing slashing units.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { Logger } from '@aztec/foundation/log';
|
|
2
|
+
import { RunningPromise } from '@aztec/foundation/promise';
|
|
3
|
+
|
|
4
|
+
import type { Abi, ContractEventName, GetContractEventsReturnType, Hex } from 'viem';
|
|
5
|
+
|
|
6
|
+
import type { ViemClient } from '../types.js';
|
|
7
|
+
|
|
8
|
+
/** Default maximum number of blocks queried per `eth_getLogs` request. */
|
|
9
|
+
const DEFAULT_MAX_BLOCK_RANGE = 100;
|
|
10
|
+
|
|
11
|
+
/** Options for {@link watchContractEvent}. */
|
|
12
|
+
export type WatchContractEventOptions = {
|
|
13
|
+
/** How often to poll for new L1 blocks, in ms. Defaults to the client's polling interval. */
|
|
14
|
+
pollingIntervalMs?: number;
|
|
15
|
+
/** Maximum number of blocks per `eth_getLogs` request; wider catch-up ranges are split into chunks. */
|
|
16
|
+
maxBlockRange?: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** Event identity and handler for {@link watchContractEvent}. */
|
|
20
|
+
export type WatchContractEventParameters<
|
|
21
|
+
TAbi extends Abi,
|
|
22
|
+
TEventName extends ContractEventName<TAbi>,
|
|
23
|
+
TStrict extends boolean | undefined = undefined,
|
|
24
|
+
> = {
|
|
25
|
+
address: Hex;
|
|
26
|
+
abi: TAbi;
|
|
27
|
+
eventName: TEventName;
|
|
28
|
+
/** Whether logs must decode against the event's indexed/non-indexed arguments (defaults to false). */
|
|
29
|
+
strict?: TStrict;
|
|
30
|
+
/** Called once per event log. Errors, thrown or from a returned promise, are caught and logged. */
|
|
31
|
+
onLog: (log: GetContractEventsReturnType<TAbi, TEventName, TStrict>[number]) => unknown;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Watches for contract events by polling `eth_blockNumber` (cached by viem per client) and fetching new logs with
|
|
36
|
+
* ranged `eth_getLogs` requests, never installing server-side filters. Server-side filters are unusable against
|
|
37
|
+
* real-world endpoints: a load balancer routes polls to backends that never saw the filter, and providers report a
|
|
38
|
+
* purged filter with error codes viem does not recognize as "filter gone", so viem's own watchers either churn
|
|
39
|
+
* recreating filters or poll a dead filter id forever while silently missing events.
|
|
40
|
+
*
|
|
41
|
+
* The block that is latest on the first poll becomes the starting cursor, so its events are reported and events from
|
|
42
|
+
* earlier blocks are not. Requests never span more than `maxBlockRange` blocks: catching up after downtime is
|
|
43
|
+
* chunked into multiple requests, and the cursor advances per successful chunk so a failure retries from where it
|
|
44
|
+
* left off on the next tick. A reorg may re-emit events and removals are never reported.
|
|
45
|
+
*
|
|
46
|
+
* @returns A function that stops the watcher.
|
|
47
|
+
*/
|
|
48
|
+
export function watchContractEvent<
|
|
49
|
+
TAbi extends Abi,
|
|
50
|
+
TEventName extends ContractEventName<TAbi>,
|
|
51
|
+
TStrict extends boolean | undefined = undefined,
|
|
52
|
+
>(
|
|
53
|
+
client: ViemClient,
|
|
54
|
+
logger: Logger,
|
|
55
|
+
params: WatchContractEventParameters<TAbi, TEventName, TStrict>,
|
|
56
|
+
options: WatchContractEventOptions = {},
|
|
57
|
+
): () => void {
|
|
58
|
+
const { address, abi, eventName, strict, onLog } = params;
|
|
59
|
+
const pollingIntervalMs = options.pollingIntervalMs ?? client.pollingInterval;
|
|
60
|
+
const maxBlockRange = BigInt(options.maxBlockRange ?? DEFAULT_MAX_BLOCK_RANGE);
|
|
61
|
+
|
|
62
|
+
const logHandlerError = (err: unknown) => logger.error(`Error handling ${eventName} L1 event`, err);
|
|
63
|
+
const deliver = (log: GetContractEventsReturnType<TAbi, TEventName, TStrict>[number]) => {
|
|
64
|
+
try {
|
|
65
|
+
const result = onLog(log);
|
|
66
|
+
if (result instanceof Promise) {
|
|
67
|
+
result.catch(logHandlerError);
|
|
68
|
+
}
|
|
69
|
+
} catch (err) {
|
|
70
|
+
logHandlerError(err);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
let stopped = false;
|
|
75
|
+
let nextBlock: bigint | undefined;
|
|
76
|
+
|
|
77
|
+
const poll = async () => {
|
|
78
|
+
const latestBlock = await client.getBlockNumber();
|
|
79
|
+
if (nextBlock === undefined) {
|
|
80
|
+
nextBlock = latestBlock;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
let fromBlock: bigint = nextBlock;
|
|
84
|
+
while (fromBlock <= latestBlock && !stopped) {
|
|
85
|
+
const chunkEnd = fromBlock + maxBlockRange - 1n;
|
|
86
|
+
const toBlock = chunkEnd < latestBlock ? chunkEnd : latestBlock;
|
|
87
|
+
const logs = await client.getContractEvents<TAbi, TEventName, TStrict, bigint, bigint>({
|
|
88
|
+
address,
|
|
89
|
+
abi,
|
|
90
|
+
eventName,
|
|
91
|
+
strict,
|
|
92
|
+
fromBlock,
|
|
93
|
+
toBlock,
|
|
94
|
+
});
|
|
95
|
+
for (const log of logs) {
|
|
96
|
+
deliver(log);
|
|
97
|
+
}
|
|
98
|
+
fromBlock = toBlock + 1n;
|
|
99
|
+
nextBlock = fromBlock;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const handlePollError = (err: unknown) => logger.warn(`Error polling for ${eventName} L1 events`, { err });
|
|
104
|
+
const runner = new RunningPromise(poll, logger, pollingIntervalMs, handlePollError).start();
|
|
105
|
+
|
|
106
|
+
return () => {
|
|
107
|
+
stopped = true;
|
|
108
|
+
void runner.stop();
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -19,11 +19,11 @@ import { mainnet, sepolia } from 'viem/chains';
|
|
|
19
19
|
|
|
20
20
|
import { createEthereumChain, isAnvilTestChain } from './chain.js';
|
|
21
21
|
import { createExtendedL1Client } from './client.js';
|
|
22
|
-
import type
|
|
22
|
+
import { type L1ContractsConfig, assertValidSlotDurations } from './config.js';
|
|
23
23
|
import { deployMulticall3 } from './contracts/multicall.js';
|
|
24
24
|
import { RollupContract } from './contracts/rollup.js';
|
|
25
|
+
import { resolveFoundryBinary } from './foundry_binary.js';
|
|
25
26
|
import type { L1ContractAddresses } from './l1_contract_addresses.js';
|
|
26
|
-
import type { L1TxUtilsConfig } from './l1_tx_utils/config.js';
|
|
27
27
|
import type { ExtendedViemWalletClient } from './types.js';
|
|
28
28
|
|
|
29
29
|
const logger = createLogger('ethereum:deploy_aztec_l1_contracts');
|
|
@@ -31,9 +31,9 @@ const logger = createLogger('ethereum:deploy_aztec_l1_contracts');
|
|
|
31
31
|
const JSON_DEPLOY_RESULT_PREFIX = 'JSON DEPLOY RESULT:';
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
* Runs a process
|
|
35
|
-
*
|
|
36
|
-
*
|
|
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.
|
|
37
37
|
*/
|
|
38
38
|
function runProcess<T>(
|
|
39
39
|
command: string,
|
|
@@ -49,26 +49,41 @@ function runProcess<T>(
|
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
let result: T | undefined;
|
|
52
|
+
let parseError: Error | undefined;
|
|
53
|
+
let settled = false;
|
|
52
54
|
|
|
53
55
|
readline.createInterface({ input: proc.stdout }).on('line', line => {
|
|
54
56
|
const trimmedLine = line.trim();
|
|
55
57
|
if (trimmedLine.startsWith(JSON_DEPLOY_RESULT_PREFIX)) {
|
|
56
58
|
const jsonStr = trimmedLine.slice(JSON_DEPLOY_RESULT_PREFIX.length).trim();
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
try {
|
|
60
|
+
result = JSON.parse(jsonStr);
|
|
61
|
+
} catch {
|
|
62
|
+
parseError = new Error(`Failed to parse deploy result JSON: ${jsonStr.slice(0, 200)}`);
|
|
63
|
+
}
|
|
59
64
|
} else {
|
|
60
65
|
logger.info(line);
|
|
61
66
|
}
|
|
62
67
|
});
|
|
63
|
-
readline.createInterface({ input: proc.stderr }).on('line', logger.
|
|
68
|
+
readline.createInterface({ input: proc.stderr }).on('line', logger.warn.bind(logger));
|
|
64
69
|
|
|
65
70
|
proc.on('error', error => {
|
|
71
|
+
if (settled) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
settled = true;
|
|
66
75
|
reject(new Error(`Failed to spawn ${command}: ${error.message}`));
|
|
67
76
|
});
|
|
68
77
|
|
|
69
78
|
proc.on('close', code => {
|
|
79
|
+
if (settled) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
settled = true;
|
|
70
83
|
if (code !== 0) {
|
|
71
|
-
reject(new Error(`${command} exited with code ${code}
|
|
84
|
+
reject(new Error(`${command} exited with code ${code}`));
|
|
85
|
+
} else if (parseError) {
|
|
86
|
+
reject(parseError);
|
|
72
87
|
} else {
|
|
73
88
|
resolve(result);
|
|
74
89
|
}
|
|
@@ -79,11 +94,16 @@ function runProcess<T>(
|
|
|
79
94
|
|
|
80
95
|
// Covers an edge where where we may have a cached BlobLib that is not meant for production.
|
|
81
96
|
// Despite the profile apparently sometimes cached code remains (so says Lasse after his ignition-monorepo arc).
|
|
82
|
-
async function maybeForgeForceProductionBuild(
|
|
97
|
+
async function maybeForgeForceProductionBuild(
|
|
98
|
+
forgeBin: string,
|
|
99
|
+
l1ContractsPath: string,
|
|
100
|
+
script: string,
|
|
101
|
+
chainId: number,
|
|
102
|
+
) {
|
|
83
103
|
if (chainId === mainnet.id) {
|
|
84
104
|
logger.info(`Recompiling ${script} with production profile for mainnet deployment`);
|
|
85
105
|
logger.info('This may take a minute but ensures production BlobLib is used.');
|
|
86
|
-
await runProcess(
|
|
106
|
+
await runProcess(forgeBin, ['build', script, '--force'], { FOUNDRY_PROFILE: 'production' }, l1ContractsPath);
|
|
87
107
|
}
|
|
88
108
|
}
|
|
89
109
|
|
|
@@ -216,7 +236,6 @@ export function computeValidatorData(operator: Operator): ValidatorJson {
|
|
|
216
236
|
export interface RollupUpgradeAddresses {
|
|
217
237
|
rollupAddress: string;
|
|
218
238
|
verifierAddress: string;
|
|
219
|
-
slashFactoryAddress: string;
|
|
220
239
|
inboxAddress: string;
|
|
221
240
|
outboxAddress: string;
|
|
222
241
|
feeJuicePortalAddress: string;
|
|
@@ -229,7 +248,6 @@ export interface RollupUpgradeAddresses {
|
|
|
229
248
|
export interface ForgeRollupUpgradeResult {
|
|
230
249
|
rollupAddress: Hex;
|
|
231
250
|
verifierAddress: Hex;
|
|
232
|
-
slashFactoryAddress: Hex;
|
|
233
251
|
inboxAddress: Hex;
|
|
234
252
|
outboxAddress: Hex;
|
|
235
253
|
feeJuicePortalAddress: Hex;
|
|
@@ -270,6 +288,7 @@ export async function deployAztecL1Contracts(
|
|
|
270
288
|
args: DeployAztecL1ContractsArgs,
|
|
271
289
|
): Promise<DeployAztecL1ContractsReturnType> {
|
|
272
290
|
logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`);
|
|
291
|
+
assertValidSlotDurations(args);
|
|
273
292
|
if (args.initialValidators && args.initialValidators.length > 0 && args.existingTokenAddress) {
|
|
274
293
|
throw new Error(
|
|
275
294
|
'Cannot deploy with both initialValidators and existingTokenAddress. ' +
|
|
@@ -307,8 +326,9 @@ export async function deployAztecL1Contracts(
|
|
|
307
326
|
// Use foundry-artifacts from l1-artifacts package
|
|
308
327
|
const l1ContractsPath = prepareL1ContractsForDeployment();
|
|
309
328
|
|
|
329
|
+
const forgeBin = resolveFoundryBinary('forge');
|
|
310
330
|
const FORGE_SCRIPT = 'script/deploy/DeployAztecL1Contracts.s.sol';
|
|
311
|
-
await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
331
|
+
await maybeForgeForceProductionBuild(forgeBin, l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
312
332
|
|
|
313
333
|
// Verify contracts on Etherscan when on mainnet/sepolia and ETHERSCAN_API_KEY is available.
|
|
314
334
|
const isVerifiableChain = chainId === mainnet.id || chainId === sepolia.id;
|
|
@@ -321,11 +341,8 @@ export async function deployAztecL1Contracts(
|
|
|
321
341
|
);
|
|
322
342
|
}
|
|
323
343
|
|
|
324
|
-
|
|
325
|
-
const MAGIC_ANVIL_BATCH_SIZE = 8;
|
|
326
|
-
// Anvil seems to stall with unbounded batch size. Otherwise no max batch size is desirable.
|
|
344
|
+
const scriptPath = join(getL1ContractsPath(), 'scripts', 'forge_broadcast.js');
|
|
327
345
|
const forgeArgs = [
|
|
328
|
-
'script',
|
|
329
346
|
FORGE_SCRIPT,
|
|
330
347
|
'--sig',
|
|
331
348
|
'run()',
|
|
@@ -333,18 +350,22 @@ export async function deployAztecL1Contracts(
|
|
|
333
350
|
privateKey,
|
|
334
351
|
'--rpc-url',
|
|
335
352
|
rpcUrl,
|
|
336
|
-
'--broadcast',
|
|
337
|
-
'--batch-size',
|
|
338
|
-
MAGIC_ANVIL_BATCH_SIZE.toString(),
|
|
339
353
|
...(shouldVerify ? ['--verify'] : []),
|
|
340
354
|
];
|
|
341
355
|
const forgeEnv = {
|
|
356
|
+
// Resolved forge binary picked up by forge_broadcast.js, so it works without forge on PATH.
|
|
357
|
+
FORGE_BIN: forgeBin,
|
|
342
358
|
// Env vars required by l1-contracts/script/deploy/DeploymentConfiguration.sol.
|
|
343
359
|
NETWORK: getActiveNetworkName(),
|
|
344
360
|
FOUNDRY_PROFILE: chainId === mainnet.id ? 'production' : undefined,
|
|
345
361
|
...getDeployAztecL1ContractsEnvVars(args),
|
|
346
362
|
};
|
|
347
|
-
const result = await runProcess<ForgeL1ContractsDeployResult>(
|
|
363
|
+
const result = await runProcess<ForgeL1ContractsDeployResult>(
|
|
364
|
+
process.execPath,
|
|
365
|
+
[scriptPath, ...forgeArgs],
|
|
366
|
+
forgeEnv,
|
|
367
|
+
l1ContractsPath,
|
|
368
|
+
);
|
|
348
369
|
if (!result) {
|
|
349
370
|
throw new Error('Forge script did not output deployment result');
|
|
350
371
|
}
|
|
@@ -390,7 +411,6 @@ export async function deployAztecL1Contracts(
|
|
|
390
411
|
governanceProposerAddress: EthAddress.fromString(result.governanceProposerAddress),
|
|
391
412
|
governanceAddress: EthAddress.fromString(result.governanceAddress),
|
|
392
413
|
stakingAssetAddress: EthAddress.fromString(result.stakingAssetAddress),
|
|
393
|
-
slashFactoryAddress: result.slashFactoryAddress ? EthAddress.fromString(result.slashFactoryAddress) : undefined,
|
|
394
414
|
feeAssetHandlerAddress: result.feeAssetHandlerAddress
|
|
395
415
|
? EthAddress.fromString(result.feeAssetHandlerAddress)
|
|
396
416
|
: undefined,
|
|
@@ -477,7 +497,25 @@ export type VerificationRecord = {
|
|
|
477
497
|
libraries: VerificationLibraryEntry[];
|
|
478
498
|
};
|
|
479
499
|
|
|
480
|
-
export interface DeployAztecL1ContractsArgs
|
|
500
|
+
export interface DeployAztecL1ContractsArgs
|
|
501
|
+
extends Omit<
|
|
502
|
+
L1ContractsConfig,
|
|
503
|
+
| 'gasLimitBufferPercentage'
|
|
504
|
+
| 'maxGwei'
|
|
505
|
+
| 'maxBlobGwei'
|
|
506
|
+
| 'priorityFeeBumpPercentage'
|
|
507
|
+
| 'priorityFeeRetryBumpPercentage'
|
|
508
|
+
| 'minimumPriorityFeePerGas'
|
|
509
|
+
| 'maxSpeedUpAttempts'
|
|
510
|
+
| 'checkIntervalMs'
|
|
511
|
+
| 'stallTimeMs'
|
|
512
|
+
| 'txTimeoutMs'
|
|
513
|
+
| 'cancelTxOnTimeout'
|
|
514
|
+
| 'txCancellationFinalTimeoutMs'
|
|
515
|
+
| 'txUnseenConsideredDroppedMs'
|
|
516
|
+
| 'enableDelayer'
|
|
517
|
+
| 'txDelayerMaxInclusionTimeIntoSlot'
|
|
518
|
+
> {
|
|
481
519
|
/** The vk tree root. */
|
|
482
520
|
vkTreeRoot: Fr;
|
|
483
521
|
/** The hash of the protocol contracts. */
|
|
@@ -554,7 +592,7 @@ export function getDeployRollupForUpgradeEnvVars(
|
|
|
554
592
|
AZTEC_EXIT_DELAY_SECONDS: args.exitDelaySeconds.toString(),
|
|
555
593
|
AZTEC_PROVING_COST_PER_MANA: args.provingCostPerMana.toString(),
|
|
556
594
|
AZTEC_INITIAL_ETH_PER_FEE_ASSET: args.initialEthPerFeeAsset.toString(),
|
|
557
|
-
|
|
595
|
+
AZTEC_SLASHER_ENABLED: args.slasherEnabled ? 'true' : 'false',
|
|
558
596
|
AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS: args.slashingRoundSizeInEpochs.toString(),
|
|
559
597
|
AZTEC_SLASHING_QUORUM: args.slashingQuorum?.toString(),
|
|
560
598
|
AZTEC_SLASHING_OFFSET_IN_ROUNDS: args.slashingOffsetInRounds.toString(),
|
|
@@ -584,21 +622,15 @@ export const deployRollupForUpgrade = async (
|
|
|
584
622
|
// Use foundry-artifacts from l1-artifacts package
|
|
585
623
|
const l1ContractsPath = prepareL1ContractsForDeployment();
|
|
586
624
|
|
|
625
|
+
const forgeBin = resolveFoundryBinary('forge');
|
|
587
626
|
const FORGE_SCRIPT = 'script/deploy/DeployRollupForUpgrade.s.sol';
|
|
588
|
-
await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
627
|
+
await maybeForgeForceProductionBuild(forgeBin, l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
589
628
|
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
FORGE_SCRIPT,
|
|
593
|
-
'--sig',
|
|
594
|
-
'run()',
|
|
595
|
-
'--private-key',
|
|
596
|
-
privateKey,
|
|
597
|
-
'--rpc-url',
|
|
598
|
-
rpcUrl,
|
|
599
|
-
'--broadcast',
|
|
600
|
-
];
|
|
629
|
+
const scriptPath = join(getL1ContractsPath(), 'scripts', 'forge_broadcast.js');
|
|
630
|
+
const forgeArgs = [FORGE_SCRIPT, '--sig', 'run()', '--private-key', privateKey, '--rpc-url', rpcUrl];
|
|
601
631
|
const forgeEnv = {
|
|
632
|
+
// Resolved forge binary picked up by forge_broadcast.js, so it works without forge on PATH.
|
|
633
|
+
FORGE_BIN: forgeBin,
|
|
602
634
|
FOUNDRY_PROFILE: chainId === mainnet.id ? 'production' : undefined,
|
|
603
635
|
// Env vars required by l1-contracts/script/deploy/RollupConfiguration.sol.
|
|
604
636
|
REGISTRY_ADDRESS: registryAddress.toString(),
|
|
@@ -606,7 +638,12 @@ export const deployRollupForUpgrade = async (
|
|
|
606
638
|
...getDeployRollupForUpgradeEnvVars(args),
|
|
607
639
|
};
|
|
608
640
|
|
|
609
|
-
const result = await runProcess<ForgeRollupUpgradeResult>(
|
|
641
|
+
const result = await runProcess<ForgeRollupUpgradeResult>(
|
|
642
|
+
process.execPath,
|
|
643
|
+
[scriptPath, ...forgeArgs],
|
|
644
|
+
forgeEnv,
|
|
645
|
+
l1ContractsPath,
|
|
646
|
+
);
|
|
610
647
|
if (!result) {
|
|
611
648
|
throw new Error('Forge script did not output deployment result');
|
|
612
649
|
}
|
|
@@ -618,6 +655,5 @@ export const deployRollupForUpgrade = async (
|
|
|
618
655
|
|
|
619
656
|
return {
|
|
620
657
|
rollup,
|
|
621
|
-
slashFactoryAddress: result.slashFactoryAddress,
|
|
622
658
|
};
|
|
623
659
|
};
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
} from './deploy_aztec_l1_contracts.js';
|
|
25
25
|
import { RegisterNewRollupVersionPayloadArtifact } from './l1_artifacts.js';
|
|
26
26
|
import { type L1TxUtilsConfig, getL1TxUtilsConfigEnvVars } from './l1_tx_utils/config.js';
|
|
27
|
-
import {
|
|
27
|
+
import { createL1TxUtils } from './l1_tx_utils/factory.js';
|
|
28
28
|
import type { L1TxUtils } from './l1_tx_utils/l1_tx_utils.js';
|
|
29
29
|
import type { GasPrice, L1TxConfig, L1TxRequest } from './l1_tx_utils/types.js';
|
|
30
30
|
import type { ExtendedViemWalletClient } from './types.js';
|
|
@@ -46,7 +46,7 @@ export class L1Deployer {
|
|
|
46
46
|
private createVerificationJson: boolean = false,
|
|
47
47
|
) {
|
|
48
48
|
this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), { size: 32 }) : undefined;
|
|
49
|
-
this.l1TxUtils =
|
|
49
|
+
this.l1TxUtils = createL1TxUtils(
|
|
50
50
|
this.client,
|
|
51
51
|
{ logger: this.logger, dateProvider },
|
|
52
52
|
{ ...this.txUtilsConfig, debugMaxGasLimit: acceleratedTestDeployments },
|
|
@@ -179,7 +179,7 @@ export async function deployL1Contract(
|
|
|
179
179
|
|
|
180
180
|
if (!l1TxUtils) {
|
|
181
181
|
const config = getL1TxUtilsConfigEnvVars();
|
|
182
|
-
l1TxUtils =
|
|
182
|
+
l1TxUtils = createL1TxUtils(
|
|
183
183
|
extendedClient,
|
|
184
184
|
{ logger },
|
|
185
185
|
{ ...config, debugMaxGasLimit: acceleratedTestDeployments },
|