@aztec/ethereum 0.0.1-commit.993d52e → 0.0.1-commit.9a89641
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 +25 -3
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +60 -8
- package/dest/config.d.ts +27 -8
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +60 -13
- 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/empire_base.d.ts +1 -3
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/fee_asset_price_oracle.d.ts +6 -2
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -1
- package/dest/contracts/fee_asset_price_oracle.js +11 -6
- package/dest/contracts/governance.d.ts +135 -35
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +226 -15
- package/dest/contracts/governance_proposer.d.ts +33 -4
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +52 -13
- package/dest/contracts/gse.d.ts +8 -2
- package/dest/contracts/gse.d.ts.map +1 -1
- package/dest/contracts/gse.js +11 -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 +3 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +2 -2
- package/dest/contracts/multicall.d.ts +130 -13
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +203 -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/rollup.d.ts +5423 -27
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +396 -73
- package/dest/contracts/slashing_proposer.d.ts +170 -0
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/slashing_proposer.js +748 -0
- package/dest/deploy_aztec_l1_contracts.d.ts +18 -10
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +28 -17
- 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/l1_artifacts.d.ts +14943 -16270
- 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.js +3 -3
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +23 -4
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_fee_analyzer.js +65 -3
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +9 -1
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +138 -57
- 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 +10 -5
- package/dest/l1_tx_utils/tx_delayer.d.ts +5 -3
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -1
- package/dest/l1_tx_utils/tx_delayer.js +7 -5
- package/dest/l1_tx_utils/types.d.ts +27 -1
- package/dest/l1_tx_utils/types.d.ts.map +1 -1
- package/dest/l1_tx_utils/types.js +10 -0
- 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 +69 -4
- 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 +37 -6
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +89 -41
- package/dest/test/index.d.ts +2 -1
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +1 -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/utils.d.ts +9 -2
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +48 -16
- package/package.json +6 -9
- package/src/client.ts +66 -2
- package/src/config.ts +83 -17
- package/src/contracts/chain_state_override.ts +200 -0
- package/src/contracts/empire_base.ts +0 -2
- package/src/contracts/fee_asset_price_oracle.ts +10 -5
- package/src/contracts/governance.ts +310 -10
- package/src/contracts/governance_proposer.ts +56 -13
- package/src/contracts/gse.ts +19 -2
- package/src/contracts/inbox.ts +13 -5
- package/src/contracts/index.ts +2 -2
- package/src/contracts/multicall.ts +247 -106
- package/src/contracts/outbox.ts +42 -8
- package/src/contracts/rollup.ts +447 -80
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +91 -30
- package/src/deploy_aztec_l1_contracts.ts +32 -18
- package/src/foundry_binary.ts +57 -0
- 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 +3 -3
- package/src/l1_tx_utils/l1_fee_analyzer.ts +75 -3
- package/src/l1_tx_utils/l1_tx_utils.ts +122 -48
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +10 -5
- package/src/l1_tx_utils/tx_delayer.ts +16 -7
- package/src/l1_tx_utils/types.ts +32 -0
- package/src/publisher_manager.ts +143 -12
- package/src/queries.ts +76 -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 +82 -45
- package/src/test/index.ts +1 -0
- package/src/test/rollup_cheat_codes.ts +115 -6
- package/src/test/start_anvil.ts +212 -32
- package/src/utils.ts +45 -18
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -69
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -216
- 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/generated/l1-contracts-defaults.d.ts +0 -30
- package/dest/generated/l1-contracts-defaults.d.ts.map +0 -1
- package/dest/generated/l1-contracts-defaults.js +0 -30
- package/src/contracts/empire_slashing_proposer.ts +0 -265
- package/src/generated/l1-contracts-defaults.ts +0 -32
|
@@ -3,11 +3,12 @@ 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';
|
|
8
9
|
import { hexToBuffer } from '@aztec/foundation/string';
|
|
9
10
|
import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
|
|
10
|
-
import {
|
|
11
|
+
import { SlashingProposerAbi } from '@aztec/l1-artifacts/SlashingProposerAbi';
|
|
11
12
|
|
|
12
13
|
import {
|
|
13
14
|
type GetContractReturnType,
|
|
@@ -19,13 +20,19 @@ import {
|
|
|
19
20
|
} from 'viem';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
|
-
* Wrapper around the
|
|
23
|
+
* Wrapper around the SlashingProposer contract that provides
|
|
23
24
|
* a TypeScript interface for interacting with the consensus-based slashing system.
|
|
24
25
|
*/
|
|
25
|
-
export class
|
|
26
|
-
private readonly contract: GetContractReturnType<typeof
|
|
26
|
+
export class SlashingProposerContract {
|
|
27
|
+
private readonly contract: GetContractReturnType<typeof SlashingProposerAbi, ViemClient>;
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Slash target validators of the last round asked for. Safe to cache because a round's targets are the committees
|
|
31
|
+
* of epochs that had already ended when the round opened (see SLASH_OFFSET_IN_ROUNDS), and those committees are
|
|
32
|
+
* sampled from validator set and randao snapshots taken before the epoch started, so they cannot change while the
|
|
33
|
+
* round is live. The promise is cached rather than the result, so concurrent callers share one in-flight read.
|
|
34
|
+
*/
|
|
35
|
+
private slashTargetValidators: { round: bigint; validators: Promise<EthAddress[]> } | undefined;
|
|
29
36
|
|
|
30
37
|
constructor(
|
|
31
38
|
public readonly client: ViemClient,
|
|
@@ -33,7 +40,7 @@ export class TallySlashingProposerContract {
|
|
|
33
40
|
) {
|
|
34
41
|
this.contract = getContract({
|
|
35
42
|
address: typeof address === 'string' ? address : address.toString(),
|
|
36
|
-
abi:
|
|
43
|
+
abi: SlashingProposerAbi,
|
|
37
44
|
client,
|
|
38
45
|
});
|
|
39
46
|
}
|
|
@@ -66,6 +73,8 @@ export class TallySlashingProposerContract {
|
|
|
66
73
|
return this.contract.read.EXECUTION_DELAY_IN_ROUNDS();
|
|
67
74
|
}
|
|
68
75
|
|
|
76
|
+
/** Returns the slash amounts for the three slash unit levels. Immutable on the contract, so memoized. */
|
|
77
|
+
@memoize
|
|
69
78
|
public getSlashingAmounts(): Promise<[bigint, bigint, bigint]> {
|
|
70
79
|
return Promise.all([
|
|
71
80
|
this.contract.read.SLASH_AMOUNT_SMALL(),
|
|
@@ -136,12 +145,12 @@ export class TallySlashingProposerContract {
|
|
|
136
145
|
|
|
137
146
|
/** Tries to extract a VoteCast event from the given logs. */
|
|
138
147
|
public tryExtractVoteCastEvent(logs: Log[]) {
|
|
139
|
-
return tryExtractEvent(logs, this.address.toString(),
|
|
148
|
+
return tryExtractEvent(logs, this.address.toString(), SlashingProposerAbi, 'VoteCast');
|
|
140
149
|
}
|
|
141
150
|
|
|
142
151
|
/** Tries to extract a RoundExecuted event from the given logs. */
|
|
143
152
|
public tryExtractRoundExecutedEvent(logs: Log[]) {
|
|
144
|
-
return tryExtractEvent(logs, this.address.toString(),
|
|
153
|
+
return tryExtractEvent(logs, this.address.toString(), SlashingProposerAbi, 'RoundExecuted');
|
|
145
154
|
}
|
|
146
155
|
|
|
147
156
|
/**
|
|
@@ -161,9 +170,9 @@ export class TallySlashingProposerContract {
|
|
|
161
170
|
|
|
162
171
|
return {
|
|
163
172
|
to: this.contract.address,
|
|
164
|
-
abi:
|
|
173
|
+
abi: SlashingProposerAbi,
|
|
165
174
|
data: encodeFunctionData({
|
|
166
|
-
abi:
|
|
175
|
+
abi: SlashingProposerAbi,
|
|
167
176
|
functionName: 'vote',
|
|
168
177
|
args: [votes, signature.toViemSignature()],
|
|
169
178
|
}),
|
|
@@ -173,7 +182,7 @@ export class TallySlashingProposerContract {
|
|
|
173
182
|
/** Returns the typed data definition to EIP712-sign for voting */
|
|
174
183
|
public buildVoteTypedData(votes: Hex, slot: SlotNumber): TypedDataDefinition {
|
|
175
184
|
const domain = {
|
|
176
|
-
name: '
|
|
185
|
+
name: 'SlashingProposer',
|
|
177
186
|
version: '1',
|
|
178
187
|
chainId: this.client.chain.id,
|
|
179
188
|
verifyingContract: this.contract.address,
|
|
@@ -209,9 +218,9 @@ export class TallySlashingProposerContract {
|
|
|
209
218
|
public buildVoteRequestWithSignature(votes: Hex, signature: { v: number; r: Hex; s: Hex }): L1TxRequest {
|
|
210
219
|
return {
|
|
211
220
|
to: this.contract.address,
|
|
212
|
-
abi:
|
|
221
|
+
abi: SlashingProposerAbi,
|
|
213
222
|
data: encodeFunctionData({
|
|
214
|
-
abi:
|
|
223
|
+
abi: SlashingProposerAbi,
|
|
215
224
|
functionName: 'vote',
|
|
216
225
|
args: [votes, signature],
|
|
217
226
|
}),
|
|
@@ -227,44 +236,79 @@ export class TallySlashingProposerContract {
|
|
|
227
236
|
public buildExecuteRoundRequest(round: bigint, committees: EthAddress[][]): L1TxRequest {
|
|
228
237
|
return {
|
|
229
238
|
to: this.contract.address,
|
|
230
|
-
abi: mergeAbis([
|
|
239
|
+
abi: mergeAbis([SlashingProposerAbi, SlasherAbi]),
|
|
231
240
|
data: encodeFunctionData({
|
|
232
|
-
abi:
|
|
241
|
+
abi: SlashingProposerAbi,
|
|
233
242
|
functionName: 'executeRound',
|
|
234
243
|
args: [round, committees.map(c => c.map(addr => addr.toString()))],
|
|
235
244
|
}),
|
|
236
245
|
};
|
|
237
246
|
}
|
|
238
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Returns the validators eligible to be voted against in a round, in the order votes encode them. Cached for the
|
|
250
|
+
* last round asked for: reading them runs a committee sampling simulation on L1, and every vote of a round decodes
|
|
251
|
+
* against the same list, so a caller walking a round's votes would otherwise repeat that call per vote. Only the
|
|
252
|
+
* last round is kept since callers move forward round by round.
|
|
253
|
+
*/
|
|
254
|
+
public getSlashTargetValidators(round: bigint): Promise<EthAddress[]> {
|
|
255
|
+
const cached = this.slashTargetValidators;
|
|
256
|
+
if (cached?.round === round) {
|
|
257
|
+
return cached.validators;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const entry = { round, validators: this.fetchSlashTargetValidators(round) };
|
|
261
|
+
this.slashTargetValidators = entry;
|
|
262
|
+
// A failed read must not stay cached, or every later vote of the round would replay the same rejection
|
|
263
|
+
entry.validators.catch(() => {
|
|
264
|
+
if (this.slashTargetValidators === entry) {
|
|
265
|
+
this.slashTargetValidators = undefined;
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
return entry.validators;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private async fetchSlashTargetValidators(round: bigint): Promise<EthAddress[]> {
|
|
272
|
+
const { result } = await this.contract.simulate.getSlashTargetCommittees([round]);
|
|
273
|
+
return result.flat().map(validator => EthAddress.fromString(validator));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Returns the slash amount voted for each target validator by a single vote of a round.
|
|
278
|
+
* @param index - Position of the vote within the round, from 0 (inclusive) to the round's vote count (exclusive)
|
|
279
|
+
*/
|
|
280
|
+
public async getVoteAt(round: bigint, index: bigint): Promise<SlashVoteTarget[]> {
|
|
281
|
+
const [validators, vote, slashAmounts] = await Promise.all([
|
|
282
|
+
this.getSlashTargetValidators(round),
|
|
283
|
+
this.contract.read.getVotes([round, index]),
|
|
284
|
+
this.getSlashingAmounts(),
|
|
285
|
+
]);
|
|
286
|
+
return decodeVote(vote, validators, slashAmounts);
|
|
287
|
+
}
|
|
288
|
+
|
|
239
289
|
/** Returns the last vote emitted for a given round */
|
|
240
290
|
public async getLastVote(round: bigint) {
|
|
241
291
|
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);
|
|
292
|
+
return await this.getVoteAt(round, voteCount - 1n);
|
|
252
293
|
}
|
|
253
294
|
|
|
254
295
|
/**
|
|
255
296
|
* Listen for VoteCast events
|
|
256
|
-
* @param callback - Callback
|
|
297
|
+
* @param callback - Callback receiving the round, the vote's index within the round as accepted by `getVoteAt`,
|
|
298
|
+
* and the proposer that cast it
|
|
257
299
|
* @returns Unwatch function
|
|
258
300
|
*/
|
|
259
|
-
public listenToVoteCast(
|
|
301
|
+
public listenToVoteCast(
|
|
302
|
+
callback: (args: { round: bigint; voteIndex: bigint; proposer: string }) => void,
|
|
303
|
+
): () => void {
|
|
260
304
|
return this.contract.watchEvent.VoteCast(
|
|
261
305
|
{},
|
|
262
306
|
{
|
|
263
307
|
onLogs: logs => {
|
|
264
308
|
for (const log of logs) {
|
|
265
|
-
const { round, proposer } = log.args;
|
|
266
|
-
if (round !== undefined && proposer) {
|
|
267
|
-
callback({ round, proposer });
|
|
309
|
+
const { round, voteIndex, proposer } = log.args;
|
|
310
|
+
if (round !== undefined && voteIndex !== undefined && proposer) {
|
|
311
|
+
callback({ round, voteIndex, proposer });
|
|
268
312
|
}
|
|
269
313
|
}
|
|
270
314
|
},
|
|
@@ -296,6 +340,23 @@ export class TallySlashingProposerContract {
|
|
|
296
340
|
}
|
|
297
341
|
}
|
|
298
342
|
|
|
343
|
+
/**
|
|
344
|
+
* A validator targeted by a slashing vote, with the amount voted. The position is the validator's index in the
|
|
345
|
+
* round's flattened slash target committees — the unit the contract tallies quorum by. A validator sitting in
|
|
346
|
+
* several of the round's committees holds several positions, each with its own tally.
|
|
347
|
+
*/
|
|
348
|
+
export type SlashVoteTarget = { validator: EthAddress; slashAmount: bigint; position: number };
|
|
349
|
+
|
|
350
|
+
function decodeVote(vote: Hex, validators: EthAddress[], slashAmounts: [bigint, bigint, bigint]): SlashVoteTarget[] {
|
|
351
|
+
return decodeSlashConsensusVotes(hexToBuffer(vote))
|
|
352
|
+
.map((units, position) => ({
|
|
353
|
+
validator: validators[position],
|
|
354
|
+
slashAmount: slashAmounts[units - 1] ?? 0n,
|
|
355
|
+
position,
|
|
356
|
+
}))
|
|
357
|
+
.filter(v => v.slashAmount > 0n);
|
|
358
|
+
}
|
|
359
|
+
|
|
299
360
|
/**
|
|
300
361
|
* Decodes a Buffer containing slash votes back into an array of numbers.
|
|
301
362
|
* Each vote is represented as a 2-bit value (0, 1, 2, or 3) representing slashing units.
|
|
@@ -5,12 +5,12 @@ import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
|
5
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
6
|
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
7
7
|
import type { Fr } from '@aztec/foundation/schemas';
|
|
8
|
-
import { fileURLToPath } from '@aztec/foundation/url';
|
|
9
8
|
|
|
10
9
|
import { bn254 } from '@noble/curves/bn254';
|
|
11
10
|
import type { Abi, Narrow } from 'abitype';
|
|
12
11
|
import { spawn } from 'child_process';
|
|
13
12
|
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs';
|
|
13
|
+
import { createRequire } from 'node:module';
|
|
14
14
|
import { tmpdir } from 'os';
|
|
15
15
|
import { dirname, join, resolve } from 'path';
|
|
16
16
|
import readline from 'readline';
|
|
@@ -19,14 +19,17 @@ 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
27
|
import type { ExtendedViemWalletClient } from './types.js';
|
|
27
28
|
|
|
28
29
|
const logger = createLogger('ethereum:deploy_aztec_l1_contracts');
|
|
29
30
|
|
|
31
|
+
const require = createRequire(import.meta.url);
|
|
32
|
+
|
|
30
33
|
const JSON_DEPLOY_RESULT_PREFIX = 'JSON DEPLOY RESULT:';
|
|
31
34
|
|
|
32
35
|
/**
|
|
@@ -93,11 +96,16 @@ function runProcess<T>(
|
|
|
93
96
|
|
|
94
97
|
// Covers an edge where where we may have a cached BlobLib that is not meant for production.
|
|
95
98
|
// Despite the profile apparently sometimes cached code remains (so says Lasse after his ignition-monorepo arc).
|
|
96
|
-
async function maybeForgeForceProductionBuild(
|
|
99
|
+
async function maybeForgeForceProductionBuild(
|
|
100
|
+
forgeBin: string,
|
|
101
|
+
l1ContractsPath: string,
|
|
102
|
+
script: string,
|
|
103
|
+
chainId: number,
|
|
104
|
+
) {
|
|
97
105
|
if (chainId === mainnet.id) {
|
|
98
106
|
logger.info(`Recompiling ${script} with production profile for mainnet deployment`);
|
|
99
107
|
logger.info('This may take a minute but ensures production BlobLib is used.');
|
|
100
|
-
await runProcess(
|
|
108
|
+
await runProcess(forgeBin, ['build', script, '--force'], { FOUNDRY_PROFILE: 'production' }, l1ContractsPath);
|
|
101
109
|
}
|
|
102
110
|
}
|
|
103
111
|
|
|
@@ -123,15 +131,13 @@ export interface ValidatorJson {
|
|
|
123
131
|
}
|
|
124
132
|
|
|
125
133
|
/**
|
|
126
|
-
* Gets the path to the l1-contracts foundry artifacts directory.
|
|
127
|
-
*
|
|
128
|
-
*
|
|
134
|
+
* Gets the path to the l1-contracts foundry artifacts directory bundled inside @aztec/l1-artifacts.
|
|
135
|
+
* Resolved through the package (its "." export -> dest/index.js) so it works whether the package is
|
|
136
|
+
* linked via portal (monorepo) or installed under node_modules (published npm) — resolution follows
|
|
137
|
+
* the symlink in the portal case. The bundled foundry subtree sits alongside dest/, at <pkg>/l1-contracts.
|
|
129
138
|
*/
|
|
130
139
|
export function getL1ContractsPath(): string {
|
|
131
|
-
|
|
132
|
-
// Go up from yarn-project/ethereum/dest to yarn-project, then to l1-artifacts/l1-contracts
|
|
133
|
-
const l1ContractsPath = resolve(currentDir, '..', '..', 'l1-artifacts', 'l1-contracts');
|
|
134
|
-
return l1ContractsPath;
|
|
140
|
+
return resolve(dirname(require.resolve('@aztec/l1-artifacts')), '..', 'l1-contracts');
|
|
135
141
|
}
|
|
136
142
|
|
|
137
143
|
// Cached deployment directory
|
|
@@ -230,7 +236,6 @@ export function computeValidatorData(operator: Operator): ValidatorJson {
|
|
|
230
236
|
export interface RollupUpgradeAddresses {
|
|
231
237
|
rollupAddress: string;
|
|
232
238
|
verifierAddress: string;
|
|
233
|
-
slashFactoryAddress: string;
|
|
234
239
|
inboxAddress: string;
|
|
235
240
|
outboxAddress: string;
|
|
236
241
|
feeJuicePortalAddress: string;
|
|
@@ -243,7 +248,6 @@ export interface RollupUpgradeAddresses {
|
|
|
243
248
|
export interface ForgeRollupUpgradeResult {
|
|
244
249
|
rollupAddress: Hex;
|
|
245
250
|
verifierAddress: Hex;
|
|
246
|
-
slashFactoryAddress: Hex;
|
|
247
251
|
inboxAddress: Hex;
|
|
248
252
|
outboxAddress: Hex;
|
|
249
253
|
feeJuicePortalAddress: Hex;
|
|
@@ -284,6 +288,7 @@ export async function deployAztecL1Contracts(
|
|
|
284
288
|
args: DeployAztecL1ContractsArgs,
|
|
285
289
|
): Promise<DeployAztecL1ContractsReturnType> {
|
|
286
290
|
logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`);
|
|
291
|
+
assertValidSlotDurations(args);
|
|
287
292
|
if (args.initialValidators && args.initialValidators.length > 0 && args.existingTokenAddress) {
|
|
288
293
|
throw new Error(
|
|
289
294
|
'Cannot deploy with both initialValidators and existingTokenAddress. ' +
|
|
@@ -321,8 +326,9 @@ export async function deployAztecL1Contracts(
|
|
|
321
326
|
// Use foundry-artifacts from l1-artifacts package
|
|
322
327
|
const l1ContractsPath = prepareL1ContractsForDeployment();
|
|
323
328
|
|
|
329
|
+
const forgeBin = resolveFoundryBinary('forge');
|
|
324
330
|
const FORGE_SCRIPT = 'script/deploy/DeployAztecL1Contracts.s.sol';
|
|
325
|
-
await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
331
|
+
await maybeForgeForceProductionBuild(forgeBin, l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
326
332
|
|
|
327
333
|
// Verify contracts on Etherscan when on mainnet/sepolia and ETHERSCAN_API_KEY is available.
|
|
328
334
|
const isVerifiableChain = chainId === mainnet.id || chainId === sepolia.id;
|
|
@@ -347,6 +353,8 @@ export async function deployAztecL1Contracts(
|
|
|
347
353
|
...(shouldVerify ? ['--verify'] : []),
|
|
348
354
|
];
|
|
349
355
|
const forgeEnv = {
|
|
356
|
+
// Resolved forge binary picked up by forge_broadcast.js, so it works without forge on PATH.
|
|
357
|
+
FORGE_BIN: forgeBin,
|
|
350
358
|
// Env vars required by l1-contracts/script/deploy/DeploymentConfiguration.sol.
|
|
351
359
|
NETWORK: getActiveNetworkName(),
|
|
352
360
|
FOUNDRY_PROFILE: chainId === mainnet.id ? 'production' : undefined,
|
|
@@ -403,7 +411,6 @@ export async function deployAztecL1Contracts(
|
|
|
403
411
|
governanceProposerAddress: EthAddress.fromString(result.governanceProposerAddress),
|
|
404
412
|
governanceAddress: EthAddress.fromString(result.governanceAddress),
|
|
405
413
|
stakingAssetAddress: EthAddress.fromString(result.stakingAssetAddress),
|
|
406
|
-
slashFactoryAddress: result.slashFactoryAddress ? EthAddress.fromString(result.slashFactoryAddress) : undefined,
|
|
407
414
|
feeAssetHandlerAddress: result.feeAssetHandlerAddress
|
|
408
415
|
? EthAddress.fromString(result.feeAssetHandlerAddress)
|
|
409
416
|
: undefined,
|
|
@@ -585,13 +592,18 @@ export function getDeployRollupForUpgradeEnvVars(
|
|
|
585
592
|
AZTEC_EXIT_DELAY_SECONDS: args.exitDelaySeconds.toString(),
|
|
586
593
|
AZTEC_PROVING_COST_PER_MANA: args.provingCostPerMana.toString(),
|
|
587
594
|
AZTEC_INITIAL_ETH_PER_FEE_ASSET: args.initialEthPerFeeAsset.toString(),
|
|
588
|
-
|
|
595
|
+
AZTEC_SLASHER_ENABLED: args.slasherEnabled ? 'true' : 'false',
|
|
589
596
|
AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS: args.slashingRoundSizeInEpochs.toString(),
|
|
590
597
|
AZTEC_SLASHING_QUORUM: args.slashingQuorum?.toString(),
|
|
591
598
|
AZTEC_SLASHING_OFFSET_IN_ROUNDS: args.slashingOffsetInRounds.toString(),
|
|
592
599
|
AZTEC_SLASH_AMOUNT_SMALL: args.slashAmountSmall.toString(),
|
|
593
600
|
AZTEC_SLASH_AMOUNT_MEDIUM: args.slashAmountMedium.toString(),
|
|
594
601
|
AZTEC_SLASH_AMOUNT_LARGE: args.slashAmountLarge.toString(),
|
|
602
|
+
AZTEC_ENTRY_QUEUE_BOOTSTRAP_VALIDATOR_SET_SIZE: args.entryQueueBootstrapValidatorSetSize.toString(),
|
|
603
|
+
AZTEC_ENTRY_QUEUE_BOOTSTRAP_FLUSH_SIZE: args.entryQueueBootstrapFlushSize.toString(),
|
|
604
|
+
AZTEC_ENTRY_QUEUE_FLUSH_SIZE_MIN: args.entryQueueFlushSizeMin.toString(),
|
|
605
|
+
AZTEC_ENTRY_QUEUE_FLUSH_SIZE_QUOTIENT: args.entryQueueFlushSizeQuotient.toString(),
|
|
606
|
+
AZTEC_ENTRY_QUEUE_MAX_FLUSH_SIZE: args.entryQueueMaxFlushSize.toString(),
|
|
595
607
|
} as const;
|
|
596
608
|
}
|
|
597
609
|
|
|
@@ -615,12 +627,15 @@ export const deployRollupForUpgrade = async (
|
|
|
615
627
|
// Use foundry-artifacts from l1-artifacts package
|
|
616
628
|
const l1ContractsPath = prepareL1ContractsForDeployment();
|
|
617
629
|
|
|
630
|
+
const forgeBin = resolveFoundryBinary('forge');
|
|
618
631
|
const FORGE_SCRIPT = 'script/deploy/DeployRollupForUpgrade.s.sol';
|
|
619
|
-
await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
632
|
+
await maybeForgeForceProductionBuild(forgeBin, l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
620
633
|
|
|
621
634
|
const scriptPath = join(getL1ContractsPath(), 'scripts', 'forge_broadcast.js');
|
|
622
635
|
const forgeArgs = [FORGE_SCRIPT, '--sig', 'run()', '--private-key', privateKey, '--rpc-url', rpcUrl];
|
|
623
636
|
const forgeEnv = {
|
|
637
|
+
// Resolved forge binary picked up by forge_broadcast.js, so it works without forge on PATH.
|
|
638
|
+
FORGE_BIN: forgeBin,
|
|
624
639
|
FOUNDRY_PROFILE: chainId === mainnet.id ? 'production' : undefined,
|
|
625
640
|
// Env vars required by l1-contracts/script/deploy/RollupConfiguration.sol.
|
|
626
641
|
REGISTRY_ADDRESS: registryAddress.toString(),
|
|
@@ -645,6 +660,5 @@ export const deployRollupForUpgrade = async (
|
|
|
645
660
|
|
|
646
661
|
return {
|
|
647
662
|
rollup,
|
|
648
|
-
slashFactoryAddress: result.slashFactoryAddress,
|
|
649
663
|
};
|
|
650
664
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { spawnSync } from 'child_process';
|
|
2
|
+
import { accessSync, constants } from 'fs';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
|
|
6
|
+
function isExecutable(path: string): boolean {
|
|
7
|
+
try {
|
|
8
|
+
accessSync(path, constants.X_OK);
|
|
9
|
+
return true;
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Locate a Foundry binary (`anvil`, `forge`, ...) without relying on the caller's PATH. Order:
|
|
17
|
+
* 1. `$<NAME>_BIN` (e.g. `$ANVIL_BIN`, `$FORGE_BIN`) — explicit override, e.g. for CI with a pinned
|
|
18
|
+
* version. Throws if set but not pointing at an executable, instead of silently falling back.
|
|
19
|
+
* 2. `~/.aztec/current/internal-bin/<name>` — where aztec-up installs it.
|
|
20
|
+
* 3. `~/.aztec/current/bin/aztec-<name>` — the publicly-exposed symlink.
|
|
21
|
+
* 4. `~/.foundry/bin/<name>` — standalone foundryup install.
|
|
22
|
+
* 5. `command -v <name>` — anything else on PATH.
|
|
23
|
+
*
|
|
24
|
+
* Throws with a directive message if none work.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveFoundryBinary(name: string): string {
|
|
27
|
+
const envVar = `${name.toUpperCase()}_BIN`;
|
|
28
|
+
const envBin = process.env[envVar];
|
|
29
|
+
if (envBin) {
|
|
30
|
+
if (!isExecutable(envBin)) {
|
|
31
|
+
throw new Error(`$${envVar} is set to ${envBin}, which does not exist or is not executable.`);
|
|
32
|
+
}
|
|
33
|
+
return envBin;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const candidates = [
|
|
37
|
+
join(homedir(), '.aztec', 'current', 'internal-bin', name),
|
|
38
|
+
join(homedir(), '.aztec', 'current', 'bin', `aztec-${name}`),
|
|
39
|
+
join(homedir(), '.foundry', 'bin', name),
|
|
40
|
+
];
|
|
41
|
+
for (const path of candidates) {
|
|
42
|
+
if (isExecutable(path)) {
|
|
43
|
+
return path;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const which = spawnSync('sh', ['-c', `command -v ${name}`], { encoding: 'utf8' });
|
|
48
|
+
if (which.status === 0 && which.stdout.trim()) {
|
|
49
|
+
return which.stdout.trim();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
throw new Error(
|
|
53
|
+
`${name} binary not found. Tried $${envVar}, ~/.aztec/current/internal-bin/${name}, ` +
|
|
54
|
+
`~/.aztec/current/bin/aztec-${name}, ~/.foundry/bin/${name}, and $PATH. ` +
|
|
55
|
+
`Install via \`aztec-up\` or set ${envVar} to a working binary.`,
|
|
56
|
+
);
|
|
57
|
+
}
|
package/src/l1_artifacts.ts
CHANGED
|
@@ -3,10 +3,6 @@ import {
|
|
|
3
3
|
CoinIssuerBytecode,
|
|
4
4
|
DateGatedRelayerAbi,
|
|
5
5
|
DateGatedRelayerBytecode,
|
|
6
|
-
EmpireSlasherDeploymentExtLibAbi,
|
|
7
|
-
EmpireSlasherDeploymentExtLibBytecode,
|
|
8
|
-
EmpireSlashingProposerAbi,
|
|
9
|
-
EmpireSlashingProposerBytecode,
|
|
10
6
|
FeeAssetHandlerAbi,
|
|
11
7
|
FeeAssetHandlerBytecode,
|
|
12
8
|
FeeJuicePortalAbi,
|
|
@@ -42,16 +38,14 @@ import {
|
|
|
42
38
|
RollupLinkReferences,
|
|
43
39
|
RollupOperationsExtLibAbi,
|
|
44
40
|
RollupOperationsExtLibBytecode,
|
|
45
|
-
SlashFactoryAbi,
|
|
46
|
-
SlashFactoryBytecode,
|
|
47
41
|
SlasherAbi,
|
|
48
42
|
SlasherBytecode,
|
|
43
|
+
SlasherDeploymentExtLibAbi,
|
|
44
|
+
SlasherDeploymentExtLibBytecode,
|
|
45
|
+
SlashingProposerAbi,
|
|
46
|
+
SlashingProposerBytecode,
|
|
49
47
|
StakingAssetHandlerAbi,
|
|
50
48
|
StakingAssetHandlerBytecode,
|
|
51
|
-
TallySlasherDeploymentExtLibAbi,
|
|
52
|
-
TallySlasherDeploymentExtLibBytecode,
|
|
53
|
-
TallySlashingProposerAbi,
|
|
54
|
-
TallySlashingProposerBytecode,
|
|
55
49
|
TestERC20Abi,
|
|
56
50
|
TestERC20Bytecode,
|
|
57
51
|
ValidatorOperationsExtLibAbi,
|
|
@@ -107,15 +101,10 @@ export const RollupArtifact = {
|
|
|
107
101
|
contractAbi: RewardExtLibAbi,
|
|
108
102
|
contractBytecode: RewardExtLibBytecode as Hex,
|
|
109
103
|
},
|
|
110
|
-
|
|
111
|
-
name: '
|
|
112
|
-
contractAbi:
|
|
113
|
-
contractBytecode:
|
|
114
|
-
},
|
|
115
|
-
EmpireSlasherDeploymentExtLib: {
|
|
116
|
-
name: 'EmpireSlasherDeploymentExtLib',
|
|
117
|
-
contractAbi: EmpireSlasherDeploymentExtLibAbi,
|
|
118
|
-
contractBytecode: EmpireSlasherDeploymentExtLibBytecode as Hex,
|
|
104
|
+
SlasherDeploymentExtLib: {
|
|
105
|
+
name: 'SlasherDeploymentExtLib',
|
|
106
|
+
contractAbi: SlasherDeploymentExtLibAbi,
|
|
107
|
+
contractBytecode: SlasherDeploymentExtLibBytecode as Hex,
|
|
119
108
|
},
|
|
120
109
|
},
|
|
121
110
|
},
|
|
@@ -175,22 +164,10 @@ export const SlasherArtifact = {
|
|
|
175
164
|
contractBytecode: SlasherBytecode as Hex,
|
|
176
165
|
};
|
|
177
166
|
|
|
178
|
-
export const
|
|
179
|
-
name: '
|
|
180
|
-
contractAbi:
|
|
181
|
-
contractBytecode:
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
export const TallySlashingProposerArtifact = {
|
|
185
|
-
name: 'TallySlashingProposer',
|
|
186
|
-
contractAbi: TallySlashingProposerAbi,
|
|
187
|
-
contractBytecode: TallySlashingProposerBytecode as Hex,
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
export const SlashFactoryArtifact = {
|
|
191
|
-
name: 'SlashFactory',
|
|
192
|
-
contractAbi: SlashFactoryAbi,
|
|
193
|
-
contractBytecode: SlashFactoryBytecode as Hex,
|
|
167
|
+
export const SlashingProposerArtifact = {
|
|
168
|
+
name: 'SlashingProposer',
|
|
169
|
+
contractAbi: SlashingProposerAbi,
|
|
170
|
+
contractBytecode: SlashingProposerBytecode as Hex,
|
|
194
171
|
};
|
|
195
172
|
|
|
196
173
|
export const RegisterNewRollupVersionPayloadArtifact = {
|