@aztec/ethereum 3.0.0-canary.a9708bd → 3.0.0-devnet.3
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 +1 -1
- package/dest/client.d.ts.map +1 -1
- package/dest/config.d.ts +11 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +124 -64
- package/dest/contracts/empire_base.d.ts +1 -1
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.d.ts +2 -2
- package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.js +1 -1
- package/dest/contracts/fee_asset_handler.d.ts +3 -3
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
- package/dest/contracts/governance.js +7 -3
- package/dest/contracts/governance_proposer.d.ts +1 -2
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +1 -2
- package/dest/contracts/multicall.d.ts +3 -5
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +6 -4
- package/dest/contracts/rollup.d.ts +39 -19
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +84 -88
- package/dest/contracts/slasher_contract.d.ts +10 -0
- package/dest/contracts/slasher_contract.d.ts.map +1 -1
- package/dest/contracts/slasher_contract.js +18 -0
- package/dest/contracts/tally_slashing_proposer.d.ts +22 -3
- package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/tally_slashing_proposer.js +55 -5
- package/dest/deploy_l1_contracts.d.ts +22 -7
- package/dest/deploy_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_l1_contracts.js +555 -362
- package/dest/index.d.ts +1 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/l1_artifacts.d.ts +8729 -6014
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +10 -5
- package/dest/l1_contract_addresses.d.ts +5 -1
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +16 -26
- package/dest/l1_reader.d.ts +1 -1
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +8 -8
- package/dest/l1_tx_utils/config.d.ts +59 -0
- package/dest/l1_tx_utils/config.d.ts.map +1 -0
- package/dest/l1_tx_utils/config.js +73 -0
- package/dest/l1_tx_utils/constants.d.ts +6 -0
- package/dest/l1_tx_utils/constants.d.ts.map +1 -0
- package/dest/l1_tx_utils/constants.js +14 -0
- package/dest/l1_tx_utils/factory.d.ts +24 -0
- package/dest/l1_tx_utils/factory.d.ts.map +1 -0
- package/dest/l1_tx_utils/factory.js +12 -0
- package/dest/l1_tx_utils/index.d.ts +10 -0
- package/dest/l1_tx_utils/index.d.ts.map +1 -0
- package/dest/l1_tx_utils/index.js +10 -0
- package/dest/l1_tx_utils/interfaces.d.ts +76 -0
- package/dest/l1_tx_utils/interfaces.d.ts.map +1 -0
- package/dest/l1_tx_utils/interfaces.js +4 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +95 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/l1_tx_utils.js +610 -0
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +26 -0
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +1 -0
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +26 -0
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +81 -0
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +294 -0
- package/dest/l1_tx_utils/signer.d.ts +4 -0
- package/dest/l1_tx_utils/signer.d.ts.map +1 -0
- package/dest/l1_tx_utils/signer.js +16 -0
- package/dest/l1_tx_utils/types.d.ts +67 -0
- package/dest/l1_tx_utils/types.d.ts.map +1 -0
- package/dest/l1_tx_utils/types.js +26 -0
- package/dest/l1_tx_utils/utils.d.ts +4 -0
- package/dest/l1_tx_utils/utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/utils.js +14 -0
- package/dest/publisher_manager.d.ts +7 -2
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +36 -8
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +11 -12
- package/dest/test/chain_monitor.d.ts +11 -0
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +81 -12
- package/dest/test/delayed_tx_utils.d.ts +2 -2
- package/dest/test/delayed_tx_utils.d.ts.map +1 -1
- package/dest/test/delayed_tx_utils.js +2 -2
- package/dest/test/eth_cheat_codes.d.ts +32 -6
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +115 -28
- package/dest/test/rollup_cheat_codes.d.ts +11 -9
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +38 -6
- package/dest/test/upgrade_utils.d.ts.map +1 -1
- package/dest/test/upgrade_utils.js +3 -2
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +10 -161
- package/dest/zkPassportVerifierAddress.js +1 -1
- package/package.json +7 -7
- package/src/client.ts +1 -1
- package/src/config.ts +136 -68
- package/src/contracts/empire_base.ts +1 -1
- package/src/contracts/empire_slashing_proposer.ts +7 -3
- package/src/contracts/fee_asset_handler.ts +1 -1
- package/src/contracts/governance.ts +3 -3
- package/src/contracts/governance_proposer.ts +3 -4
- package/src/contracts/multicall.ts +12 -10
- package/src/contracts/rollup.ts +104 -106
- package/src/contracts/slasher_contract.ts +22 -0
- package/src/contracts/tally_slashing_proposer.ts +54 -6
- package/src/deploy_l1_contracts.ts +570 -328
- package/src/index.ts +1 -1
- package/src/l1_artifacts.ts +14 -6
- package/src/l1_contract_addresses.ts +17 -26
- package/src/l1_reader.ts +9 -9
- package/src/l1_tx_utils/README.md +177 -0
- package/src/l1_tx_utils/config.ts +140 -0
- package/src/l1_tx_utils/constants.ts +18 -0
- package/src/l1_tx_utils/factory.ts +64 -0
- package/src/l1_tx_utils/index.ts +12 -0
- package/src/l1_tx_utils/interfaces.ts +86 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +718 -0
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +77 -0
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +372 -0
- package/src/l1_tx_utils/signer.ts +28 -0
- package/src/l1_tx_utils/types.ts +85 -0
- package/src/l1_tx_utils/utils.ts +16 -0
- package/src/publisher_manager.ts +51 -9
- package/src/queries.ts +13 -8
- package/src/test/chain_monitor.ts +89 -9
- package/src/test/delayed_tx_utils.ts +2 -2
- package/src/test/eth_cheat_codes.ts +142 -29
- package/src/test/rollup_cheat_codes.ts +54 -14
- package/src/test/upgrade_utils.ts +3 -2
- package/src/utils.ts +13 -185
- package/src/zkPassportVerifierAddress.ts +1 -1
- package/dest/l1_tx_utils.d.ts +0 -250
- package/dest/l1_tx_utils.d.ts.map +0 -1
- package/dest/l1_tx_utils.js +0 -826
- package/dest/l1_tx_utils_with_blobs.d.ts +0 -19
- package/dest/l1_tx_utils_with_blobs.d.ts.map +0 -1
- package/dest/l1_tx_utils_with_blobs.js +0 -85
- package/src/l1_tx_utils.ts +0 -1105
- package/src/l1_tx_utils_with_blobs.ts +0 -144
|
@@ -6,10 +6,11 @@ import type { Fr } from '@aztec/foundation/fields';
|
|
|
6
6
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
7
7
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
8
8
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
9
|
-
import
|
|
9
|
+
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
10
10
|
|
|
11
11
|
import type { Abi, Narrow } from 'abitype';
|
|
12
12
|
import { mkdir, writeFile } from 'fs/promises';
|
|
13
|
+
import chunk from 'lodash.chunk';
|
|
13
14
|
import {
|
|
14
15
|
type Chain,
|
|
15
16
|
type ContractConstructorArgs,
|
|
@@ -33,7 +34,6 @@ import { createExtendedL1Client } from './client.js';
|
|
|
33
34
|
import {
|
|
34
35
|
type L1ContractsConfig,
|
|
35
36
|
getEntryQueueConfig,
|
|
36
|
-
getGSEConfiguration,
|
|
37
37
|
getGovernanceConfiguration,
|
|
38
38
|
getRewardBoostConfig,
|
|
39
39
|
getRewardConfig,
|
|
@@ -45,6 +45,7 @@ import { RegistryContract } from './contracts/registry.js';
|
|
|
45
45
|
import { RollupContract, SlashingProposerType } from './contracts/rollup.js';
|
|
46
46
|
import {
|
|
47
47
|
CoinIssuerArtifact,
|
|
48
|
+
DateGatedRelayerArtifact,
|
|
48
49
|
FeeAssetArtifact,
|
|
49
50
|
FeeAssetHandlerArtifact,
|
|
50
51
|
GSEArtifact,
|
|
@@ -63,21 +64,19 @@ import {
|
|
|
63
64
|
import type { L1ContractAddresses } from './l1_contract_addresses.js';
|
|
64
65
|
import {
|
|
65
66
|
type GasPrice,
|
|
66
|
-
type
|
|
67
|
+
type L1TxConfig,
|
|
67
68
|
type L1TxRequest,
|
|
68
69
|
L1TxUtils,
|
|
69
70
|
type L1TxUtilsConfig,
|
|
70
71
|
createL1TxUtilsFromViemWallet,
|
|
71
72
|
getL1TxUtilsConfigEnvVars,
|
|
72
|
-
} from './l1_tx_utils.js';
|
|
73
|
+
} from './l1_tx_utils/index.js';
|
|
73
74
|
import type { ExtendedViemWalletClient } from './types.js';
|
|
74
75
|
import { formatViemError } from './utils.js';
|
|
75
76
|
import { ZK_PASSPORT_DOMAIN, ZK_PASSPORT_SCOPE, ZK_PASSPORT_VERIFIER_ADDRESS } from './zkPassportVerifierAddress.js';
|
|
76
77
|
|
|
77
78
|
export const DEPLOYER_ADDRESS: Hex = '0x4e59b44847b379578588920cA78FbF26c0B4956C';
|
|
78
79
|
|
|
79
|
-
const networkName = getActiveNetworkName();
|
|
80
|
-
|
|
81
80
|
export type Operator = {
|
|
82
81
|
attester: EthAddress;
|
|
83
82
|
withdrawer: EthAddress;
|
|
@@ -148,8 +147,8 @@ export type VerificationRecord = {
|
|
|
148
147
|
export interface DeployL1ContractsArgs extends Omit<L1ContractsConfig, keyof L1TxUtilsConfig> {
|
|
149
148
|
/** The vk tree root. */
|
|
150
149
|
vkTreeRoot: Fr;
|
|
151
|
-
/** The
|
|
152
|
-
|
|
150
|
+
/** The hash of the protocol contracts. */
|
|
151
|
+
protocolContractsHash: Fr;
|
|
153
152
|
/** The genesis root of the archive tree. */
|
|
154
153
|
genesisArchiveRoot: Fr;
|
|
155
154
|
/** The salt for CREATE2 deployment. */
|
|
@@ -166,6 +165,8 @@ export interface DeployL1ContractsArgs extends Omit<L1ContractsConfig, keyof L1T
|
|
|
166
165
|
realVerifier: boolean;
|
|
167
166
|
/** The zk passport args */
|
|
168
167
|
zkPassportArgs?: ZKPassportArgs;
|
|
168
|
+
/** If provided, use this token for BOTH fee and staking assets (skip deployments) */
|
|
169
|
+
existingTokenAddress?: EthAddress;
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
export interface ZKPassportArgs {
|
|
@@ -177,39 +178,128 @@ export interface ZKPassportArgs {
|
|
|
177
178
|
zkPassportScope?: string;
|
|
178
179
|
}
|
|
179
180
|
|
|
181
|
+
// Minimal ERC20 ABI for validation purposes. We only read view methods.
|
|
182
|
+
const ERC20_VALIDATION_ABI = [
|
|
183
|
+
{
|
|
184
|
+
type: 'function',
|
|
185
|
+
name: 'totalSupply',
|
|
186
|
+
stateMutability: 'view',
|
|
187
|
+
inputs: [],
|
|
188
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
type: 'function',
|
|
192
|
+
name: 'name',
|
|
193
|
+
stateMutability: 'view',
|
|
194
|
+
inputs: [],
|
|
195
|
+
outputs: [{ name: '', type: 'string' }],
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
type: 'function',
|
|
199
|
+
name: 'symbol',
|
|
200
|
+
stateMutability: 'view',
|
|
201
|
+
inputs: [],
|
|
202
|
+
outputs: [{ name: '', type: 'string' }],
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
type: 'function',
|
|
206
|
+
name: 'decimals',
|
|
207
|
+
stateMutability: 'view',
|
|
208
|
+
inputs: [],
|
|
209
|
+
outputs: [{ name: '', type: 'uint8' }],
|
|
210
|
+
},
|
|
211
|
+
] as const;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Validates that the provided address points to a contract that resembles an ERC20 token.
|
|
215
|
+
* Checks for contract code and attempts common ERC20 view calls.
|
|
216
|
+
* Throws an error if validation fails.
|
|
217
|
+
*/
|
|
218
|
+
export async function validateExistingErc20TokenAddress(
|
|
219
|
+
l1Client: ExtendedViemWalletClient,
|
|
220
|
+
tokenAddress: EthAddress,
|
|
221
|
+
logger: Logger,
|
|
222
|
+
): Promise<void> {
|
|
223
|
+
const addressString = tokenAddress.toString();
|
|
224
|
+
|
|
225
|
+
// Ensure there is contract code at the address
|
|
226
|
+
const code = await l1Client.getCode({ address: addressString });
|
|
227
|
+
if (!code || code === '0x') {
|
|
228
|
+
throw new Error(`No contract code found at provided token address ${addressString}`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const contract = getContract({
|
|
232
|
+
address: getAddress(addressString),
|
|
233
|
+
abi: ERC20_VALIDATION_ABI,
|
|
234
|
+
client: l1Client,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Validate all required ERC20 methods in parallel
|
|
238
|
+
const checks = [
|
|
239
|
+
contract.read.totalSupply().then(total => typeof total === 'bigint'),
|
|
240
|
+
contract.read.name().then(() => true),
|
|
241
|
+
contract.read.symbol().then(() => true),
|
|
242
|
+
contract.read.decimals().then(dec => typeof dec === 'number' || typeof dec === 'bigint'),
|
|
243
|
+
];
|
|
244
|
+
|
|
245
|
+
const results = await Promise.allSettled(checks);
|
|
246
|
+
const failedChecks = results.filter(result => result.status === 'rejected' || result.value !== true);
|
|
247
|
+
|
|
248
|
+
if (failedChecks.length > 0) {
|
|
249
|
+
throw new Error(`Address ${addressString} does not appear to implement ERC20 view methods`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
logger.verbose(`Validated existing token at ${addressString} appears to be ERC20-compatible`);
|
|
253
|
+
}
|
|
254
|
+
|
|
180
255
|
export const deploySharedContracts = async (
|
|
181
256
|
l1Client: ExtendedViemWalletClient,
|
|
182
257
|
deployer: L1Deployer,
|
|
183
258
|
args: DeployL1ContractsArgs,
|
|
184
259
|
logger: Logger,
|
|
185
260
|
) => {
|
|
186
|
-
|
|
261
|
+
const networkName = getActiveNetworkName();
|
|
262
|
+
|
|
263
|
+
logger.info(`Deploying shared contracts for network configuration: ${networkName}`);
|
|
187
264
|
|
|
188
265
|
const txHashes: Hex[] = [];
|
|
189
266
|
|
|
190
|
-
|
|
191
|
-
|
|
267
|
+
let feeAssetAddress: EthAddress;
|
|
268
|
+
let stakingAssetAddress: EthAddress;
|
|
269
|
+
if (args.existingTokenAddress) {
|
|
270
|
+
await validateExistingErc20TokenAddress(l1Client, args.existingTokenAddress, logger);
|
|
271
|
+
feeAssetAddress = args.existingTokenAddress;
|
|
272
|
+
stakingAssetAddress = args.existingTokenAddress;
|
|
273
|
+
logger.verbose(`Using existing token for fee and staking assets at ${args.existingTokenAddress}`);
|
|
274
|
+
} else {
|
|
275
|
+
const deployedFee = await deployer.deploy(FeeAssetArtifact, ['FeeJuice', 'FEE', l1Client.account.address]);
|
|
276
|
+
feeAssetAddress = deployedFee.address;
|
|
277
|
+
logger.verbose(`Deployed Fee Asset at ${feeAssetAddress}`);
|
|
192
278
|
|
|
193
|
-
|
|
194
|
-
|
|
279
|
+
const deployedStaking = await deployer.deploy(StakingAssetArtifact, ['Staking', 'STK', l1Client.account.address]);
|
|
280
|
+
stakingAssetAddress = deployedStaking.address;
|
|
281
|
+
logger.verbose(`Deployed Staking Asset at ${stakingAssetAddress}`);
|
|
195
282
|
|
|
196
|
-
|
|
283
|
+
await deployer.waitForDeployments();
|
|
284
|
+
}
|
|
197
285
|
|
|
198
|
-
const gseAddress =
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
286
|
+
const gseAddress = (
|
|
287
|
+
await deployer.deploy(GSEArtifact, [
|
|
288
|
+
l1Client.account.address,
|
|
289
|
+
stakingAssetAddress.toString(),
|
|
290
|
+
args.activationThreshold,
|
|
291
|
+
args.ejectionThreshold,
|
|
292
|
+
])
|
|
293
|
+
).address;
|
|
204
294
|
logger.verbose(`Deployed GSE at ${gseAddress}`);
|
|
205
295
|
|
|
206
|
-
const registryAddress = await deployer.deploy(RegistryArtifact, [
|
|
296
|
+
const { address: registryAddress } = await deployer.deploy(RegistryArtifact, [
|
|
207
297
|
l1Client.account.address,
|
|
208
298
|
feeAssetAddress.toString(),
|
|
209
299
|
]);
|
|
210
300
|
logger.verbose(`Deployed Registry at ${registryAddress}`);
|
|
211
301
|
|
|
212
|
-
const governanceProposerAddress = await deployer.deploy(GovernanceProposerArtifact, [
|
|
302
|
+
const { address: governanceProposerAddress } = await deployer.deploy(GovernanceProposerArtifact, [
|
|
213
303
|
registryAddress.toString(),
|
|
214
304
|
gseAddress.toString(),
|
|
215
305
|
BigInt(args.governanceProposerQuorum ?? args.governanceProposerRoundSize / 2 + 1),
|
|
@@ -219,7 +309,7 @@ export const deploySharedContracts = async (
|
|
|
219
309
|
|
|
220
310
|
// @note @LHerskind the assets are expected to be the same at some point, but for better
|
|
221
311
|
// configurability they are different for now.
|
|
222
|
-
const governanceAddress = await deployer.deploy(GovernanceArtifact, [
|
|
312
|
+
const { address: governanceAddress } = await deployer.deploy(GovernanceArtifact, [
|
|
223
313
|
stakingAssetAddress.toString(),
|
|
224
314
|
governanceProposerAddress.toString(),
|
|
225
315
|
gseAddress.toString(),
|
|
@@ -261,11 +351,13 @@ export const deploySharedContracts = async (
|
|
|
261
351
|
txHashes.push(txHash);
|
|
262
352
|
}
|
|
263
353
|
|
|
264
|
-
const coinIssuerAddress =
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
354
|
+
const coinIssuerAddress = (
|
|
355
|
+
await deployer.deploy(CoinIssuerArtifact, [
|
|
356
|
+
feeAssetAddress.toString(),
|
|
357
|
+
2n * 10n ** 17n, // hard cap of 20% per year
|
|
358
|
+
l1Client.account.address,
|
|
359
|
+
])
|
|
360
|
+
).address;
|
|
269
361
|
logger.verbose(`Deployed CoinIssuer at ${coinIssuerAddress}`);
|
|
270
362
|
|
|
271
363
|
logger.verbose(`Waiting for deployments to complete`);
|
|
@@ -277,17 +369,19 @@ export const deploySharedContracts = async (
|
|
|
277
369
|
let stakingAssetHandlerAddress: EthAddress | undefined = undefined;
|
|
278
370
|
let zkPassportVerifierAddress: EthAddress | undefined = undefined;
|
|
279
371
|
|
|
280
|
-
// Only if not on mainnet will we deploy the handlers
|
|
281
|
-
if (l1Client.chain.id !== 1) {
|
|
372
|
+
// Only if not on mainnet will we deploy the handlers, and only when we control the token
|
|
373
|
+
if (l1Client.chain.id !== 1 && !args.existingTokenAddress) {
|
|
282
374
|
/* -------------------------------------------------------------------------- */
|
|
283
375
|
/* CHEAT CODES START HERE */
|
|
284
376
|
/* -------------------------------------------------------------------------- */
|
|
285
377
|
|
|
286
|
-
feeAssetHandlerAddress =
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
378
|
+
feeAssetHandlerAddress = (
|
|
379
|
+
await deployer.deploy(FeeAssetHandlerArtifact, [
|
|
380
|
+
l1Client.account.address,
|
|
381
|
+
feeAssetAddress.toString(),
|
|
382
|
+
BigInt(1000n * 10n ** 18n),
|
|
383
|
+
])
|
|
384
|
+
).address;
|
|
291
385
|
logger.verbose(`Deployed FeeAssetHandler at ${feeAssetHandlerAddress}`);
|
|
292
386
|
|
|
293
387
|
// Only if we are "fresh" will we be adding as a minter, otherwise above will simply get same address
|
|
@@ -316,6 +410,7 @@ export const deploySharedContracts = async (
|
|
|
316
410
|
stakingAsset: stakingAssetAddress.toString(),
|
|
317
411
|
registry: registryAddress.toString(),
|
|
318
412
|
withdrawer: AMIN.toString(),
|
|
413
|
+
validatorsToFlush: 16n,
|
|
319
414
|
mintInterval: BigInt(60 * 60 * 24),
|
|
320
415
|
depositsPerMint: BigInt(10),
|
|
321
416
|
depositMerkleRoot: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
@@ -329,7 +424,8 @@ export const deploySharedContracts = async (
|
|
|
329
424
|
skipMerkleCheck: true, // skip merkle check - needed for testing without generating proofs
|
|
330
425
|
} as const;
|
|
331
426
|
|
|
332
|
-
stakingAssetHandlerAddress = await deployer.deploy(StakingAssetHandlerArtifact, [stakingAssetHandlerDeployArgs])
|
|
427
|
+
stakingAssetHandlerAddress = (await deployer.deploy(StakingAssetHandlerArtifact, [stakingAssetHandlerDeployArgs]))
|
|
428
|
+
.address;
|
|
333
429
|
logger.verbose(`Deployed StakingAssetHandler at ${stakingAssetHandlerAddress}`);
|
|
334
430
|
|
|
335
431
|
const { txHash: stakingMinterTxHash } = await deployer.sendTransaction({
|
|
@@ -365,19 +461,23 @@ export const deploySharedContracts = async (
|
|
|
365
461
|
|
|
366
462
|
const rewardDistributorAddress = await registry.getRewardDistributor();
|
|
367
463
|
|
|
368
|
-
|
|
464
|
+
if (!args.existingTokenAddress) {
|
|
465
|
+
const blockReward = getRewardConfig(networkName).blockReward;
|
|
369
466
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
467
|
+
const funding = blockReward * 200000n;
|
|
468
|
+
const { txHash: fundRewardDistributorTxHash } = await deployer.sendTransaction({
|
|
469
|
+
to: feeAssetAddress.toString(),
|
|
470
|
+
data: encodeFunctionData({
|
|
471
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
472
|
+
functionName: 'mint',
|
|
473
|
+
args: [rewardDistributorAddress.toString(), funding],
|
|
474
|
+
}),
|
|
475
|
+
});
|
|
379
476
|
|
|
380
|
-
|
|
477
|
+
logger.verbose(`Funded reward distributor with ${funding} fee asset in ${fundRewardDistributorTxHash}`);
|
|
478
|
+
} else {
|
|
479
|
+
logger.verbose(`Skipping reward distributor funding as existing token is provided`);
|
|
480
|
+
}
|
|
381
481
|
|
|
382
482
|
/* -------------------------------------------------------------------------- */
|
|
383
483
|
/* FUND REWARD DISTRIBUTOR STOP */
|
|
@@ -400,7 +500,7 @@ export const deploySharedContracts = async (
|
|
|
400
500
|
|
|
401
501
|
const getZkPassportVerifierAddress = async (deployer: L1Deployer, args: DeployL1ContractsArgs): Promise<EthAddress> => {
|
|
402
502
|
if (args.zkPassportArgs?.mockZkPassportVerifier) {
|
|
403
|
-
return await deployer.deploy(mockVerifiers.mockZkPassportVerifier);
|
|
503
|
+
return (await deployer.deploy(mockVerifiers.mockZkPassportVerifier)).address;
|
|
404
504
|
}
|
|
405
505
|
return ZK_PASSPORT_VERIFIER_ADDRESS;
|
|
406
506
|
};
|
|
@@ -416,6 +516,199 @@ const getZkPassportScopes = (args: DeployL1ContractsArgs): [string, string] => {
|
|
|
416
516
|
return [domain, scope];
|
|
417
517
|
};
|
|
418
518
|
|
|
519
|
+
/**
|
|
520
|
+
* Generates verification records for a deployed rollup and its associated contracts (Inbox, Outbox, Slasher, etc).
|
|
521
|
+
* @param rollup - The deployed rollup contract.
|
|
522
|
+
* @param deployer - The L1 deployer instance.
|
|
523
|
+
* @param args - The deployment arguments used for the rollup.
|
|
524
|
+
* @param addresses - The L1 contract addresses.
|
|
525
|
+
* @param extendedClient - The extended viem wallet client.
|
|
526
|
+
* @param logger - The logger.
|
|
527
|
+
*/
|
|
528
|
+
async function generateRollupVerificationRecords(
|
|
529
|
+
rollup: RollupContract,
|
|
530
|
+
deployer: L1Deployer,
|
|
531
|
+
args: {
|
|
532
|
+
slashingVetoer: EthAddress;
|
|
533
|
+
slashingRoundSizeInEpochs: number;
|
|
534
|
+
aztecEpochDuration: number;
|
|
535
|
+
slashingQuorum?: number;
|
|
536
|
+
slashingLifetimeInRounds: number;
|
|
537
|
+
slashingExecutionDelayInRounds: number;
|
|
538
|
+
slasherFlavor: 'none' | 'tally' | 'empire';
|
|
539
|
+
slashAmountSmall: bigint;
|
|
540
|
+
slashAmountMedium: bigint;
|
|
541
|
+
slashAmountLarge: bigint;
|
|
542
|
+
aztecTargetCommitteeSize: number;
|
|
543
|
+
slashingOffsetInRounds: number;
|
|
544
|
+
},
|
|
545
|
+
addresses: Pick<L1ContractAddresses, 'feeJuiceAddress'>,
|
|
546
|
+
extendedClient: ExtendedViemWalletClient,
|
|
547
|
+
logger: Logger,
|
|
548
|
+
): Promise<void> {
|
|
549
|
+
try {
|
|
550
|
+
// Add Inbox / Outbox verification records (constructor args are created inside RollupCore)
|
|
551
|
+
const rollupAddr = rollup.address;
|
|
552
|
+
const rollupAddresses = await rollup.getRollupAddresses();
|
|
553
|
+
const inboxAddr = rollupAddresses.inboxAddress.toString();
|
|
554
|
+
const outboxAddr = rollupAddresses.outboxAddress.toString();
|
|
555
|
+
const feeAsset = rollupAddresses.feeJuiceAddress.toString();
|
|
556
|
+
const version = await rollup.getVersion();
|
|
557
|
+
|
|
558
|
+
const inboxCtor = encodeAbiParameters(
|
|
559
|
+
[{ type: 'address' }, { type: 'address' }, { type: 'uint256' }, { type: 'uint256' }],
|
|
560
|
+
[rollupAddr, feeAsset, version, BigInt(L1_TO_L2_MSG_SUBTREE_HEIGHT)],
|
|
561
|
+
);
|
|
562
|
+
|
|
563
|
+
const outboxCtor = encodeAbiParameters([{ type: 'address' }, { type: 'uint256' }], [rollupAddr, version]);
|
|
564
|
+
|
|
565
|
+
deployer.verificationRecords.push(
|
|
566
|
+
{ name: 'Inbox', address: inboxAddr, constructorArgsHex: inboxCtor, libraries: [] },
|
|
567
|
+
{ name: 'Outbox', address: outboxAddr, constructorArgsHex: outboxCtor, libraries: [] },
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
// Include Slasher and SlashingProposer (if deployed) in verification data
|
|
571
|
+
try {
|
|
572
|
+
const slasherAddrHex = await rollup.getSlasherAddress();
|
|
573
|
+
const slasherAddr = EthAddress.fromString(slasherAddrHex);
|
|
574
|
+
if (!slasherAddr.isZero()) {
|
|
575
|
+
// Slasher constructor: (address _vetoer, address _governance)
|
|
576
|
+
const slasherCtor = encodeAbiParameters(
|
|
577
|
+
[{ type: 'address' }, { type: 'address' }],
|
|
578
|
+
[args.slashingVetoer.toString(), extendedClient.account.address],
|
|
579
|
+
);
|
|
580
|
+
deployer.verificationRecords.push({
|
|
581
|
+
name: 'Slasher',
|
|
582
|
+
address: slasherAddr.toString(),
|
|
583
|
+
constructorArgsHex: slasherCtor,
|
|
584
|
+
libraries: [],
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
// Proposer address is stored in Slasher.PROPOSER()
|
|
588
|
+
const proposerAddr = (await rollup.getSlashingProposerAddress()).toString();
|
|
589
|
+
|
|
590
|
+
// Compute constructor args matching deployment path in RollupCore
|
|
591
|
+
const computedRoundSize = BigInt(args.slashingRoundSizeInEpochs * args.aztecEpochDuration);
|
|
592
|
+
const computedQuorum = BigInt(
|
|
593
|
+
args.slashingQuorum ?? (args.slashingRoundSizeInEpochs * args.aztecEpochDuration) / 2 + 1,
|
|
594
|
+
);
|
|
595
|
+
const lifetimeInRounds = BigInt(args.slashingLifetimeInRounds);
|
|
596
|
+
const executionDelayInRounds = BigInt(args.slashingExecutionDelayInRounds);
|
|
597
|
+
|
|
598
|
+
if (args.slasherFlavor === 'tally') {
|
|
599
|
+
const slashAmounts: readonly [bigint, bigint, bigint] = [
|
|
600
|
+
args.slashAmountSmall,
|
|
601
|
+
args.slashAmountMedium,
|
|
602
|
+
args.slashAmountLarge,
|
|
603
|
+
];
|
|
604
|
+
const committeeSize = BigInt(args.aztecTargetCommitteeSize);
|
|
605
|
+
const epochDuration = BigInt(args.aztecEpochDuration);
|
|
606
|
+
const slashOffsetInRounds = BigInt(args.slashingOffsetInRounds);
|
|
607
|
+
|
|
608
|
+
const proposerCtor = encodeAbiParameters(
|
|
609
|
+
[
|
|
610
|
+
{ type: 'address' },
|
|
611
|
+
{ type: 'address' },
|
|
612
|
+
{ type: 'uint256' },
|
|
613
|
+
{ type: 'uint256' },
|
|
614
|
+
{ type: 'uint256' },
|
|
615
|
+
{ type: 'uint256' },
|
|
616
|
+
{ type: 'uint256[3]' },
|
|
617
|
+
{ type: 'uint256' },
|
|
618
|
+
{ type: 'uint256' },
|
|
619
|
+
{ type: 'uint256' },
|
|
620
|
+
],
|
|
621
|
+
[
|
|
622
|
+
rollup.address,
|
|
623
|
+
slasherAddr.toString(),
|
|
624
|
+
computedQuorum,
|
|
625
|
+
computedRoundSize,
|
|
626
|
+
lifetimeInRounds,
|
|
627
|
+
executionDelayInRounds,
|
|
628
|
+
slashAmounts,
|
|
629
|
+
committeeSize,
|
|
630
|
+
epochDuration,
|
|
631
|
+
slashOffsetInRounds,
|
|
632
|
+
],
|
|
633
|
+
);
|
|
634
|
+
|
|
635
|
+
deployer.verificationRecords.push({
|
|
636
|
+
name: 'TallySlashingProposer',
|
|
637
|
+
address: proposerAddr,
|
|
638
|
+
constructorArgsHex: proposerCtor,
|
|
639
|
+
libraries: [],
|
|
640
|
+
});
|
|
641
|
+
} else if (args.slasherFlavor === 'empire') {
|
|
642
|
+
const proposerCtor = encodeAbiParameters(
|
|
643
|
+
[
|
|
644
|
+
{ type: 'address' },
|
|
645
|
+
{ type: 'address' },
|
|
646
|
+
{ type: 'uint256' },
|
|
647
|
+
{ type: 'uint256' },
|
|
648
|
+
{ type: 'uint256' },
|
|
649
|
+
{ type: 'uint256' },
|
|
650
|
+
],
|
|
651
|
+
[
|
|
652
|
+
rollup.address,
|
|
653
|
+
slasherAddr.toString(),
|
|
654
|
+
computedQuorum,
|
|
655
|
+
computedRoundSize,
|
|
656
|
+
lifetimeInRounds,
|
|
657
|
+
executionDelayInRounds,
|
|
658
|
+
],
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
deployer.verificationRecords.push({
|
|
662
|
+
name: 'EmpireSlashingProposer',
|
|
663
|
+
address: proposerAddr,
|
|
664
|
+
constructorArgsHex: proposerCtor,
|
|
665
|
+
libraries: [],
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
} catch (e) {
|
|
670
|
+
logger.warn(`Failed to add Slasher/Proposer verification records: ${String(e)}`);
|
|
671
|
+
}
|
|
672
|
+
} catch (e) {
|
|
673
|
+
throw new Error(`Failed to generate rollup verification records: ${String(e)}`);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Writes verification records to a JSON file for later forge verify.
|
|
679
|
+
* @param deployer - The L1 deployer containing verification records.
|
|
680
|
+
* @param outputDirectory - The directory to write the verification file to.
|
|
681
|
+
* @param chainId - The chain ID.
|
|
682
|
+
* @param filenameSuffix - Optional suffix for the filename (e.g., 'upgrade').
|
|
683
|
+
* @param logger - The logger.
|
|
684
|
+
*/
|
|
685
|
+
async function writeVerificationJson(
|
|
686
|
+
deployer: L1Deployer,
|
|
687
|
+
outputDirectory: string,
|
|
688
|
+
chainId: number,
|
|
689
|
+
filenameSuffix: string = '',
|
|
690
|
+
logger: Logger,
|
|
691
|
+
): Promise<void> {
|
|
692
|
+
try {
|
|
693
|
+
const date = new Date();
|
|
694
|
+
const formattedDate = date.toISOString().slice(2, 19).replace(/[-T:]/g, '');
|
|
695
|
+
// Ensure the verification output directory exists
|
|
696
|
+
await mkdir(outputDirectory, { recursive: true });
|
|
697
|
+
const suffix = filenameSuffix ? `-${filenameSuffix}` : '';
|
|
698
|
+
const verificationOutputPath = `${outputDirectory}/l1-verify${suffix}-${chainId}-${formattedDate.slice(0, 6)}-${formattedDate.slice(6)}.json`;
|
|
699
|
+
const networkName = getActiveNetworkName();
|
|
700
|
+
const verificationData = {
|
|
701
|
+
chainId: chainId,
|
|
702
|
+
network: networkName,
|
|
703
|
+
records: deployer.verificationRecords,
|
|
704
|
+
};
|
|
705
|
+
await writeFile(verificationOutputPath, JSON.stringify(verificationData, null, 2));
|
|
706
|
+
logger.info(`Wrote L1 verification data to ${verificationOutputPath}`);
|
|
707
|
+
} catch (e) {
|
|
708
|
+
logger.warn(`Failed to write L1 verification data file: ${String(e)}`);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
419
712
|
/**
|
|
420
713
|
* Deploys a new rollup, using the existing canonical version to derive certain values (addresses of assets etc).
|
|
421
714
|
* @param clients - The L1 clients.
|
|
@@ -423,6 +716,7 @@ const getZkPassportScopes = (args: DeployL1ContractsArgs): [string, string] => {
|
|
|
423
716
|
* @param registryAddress - The address of the registry.
|
|
424
717
|
* @param logger - The logger.
|
|
425
718
|
* @param txUtilsConfig - The L1 tx utils config.
|
|
719
|
+
* @param createVerificationJson - Optional path to write verification data for forge verify.
|
|
426
720
|
*/
|
|
427
721
|
export const deployRollupForUpgrade = async (
|
|
428
722
|
extendedClient: ExtendedViemWalletClient,
|
|
@@ -433,6 +727,7 @@ export const deployRollupForUpgrade = async (
|
|
|
433
727
|
registryAddress: EthAddress,
|
|
434
728
|
logger: Logger,
|
|
435
729
|
txUtilsConfig: L1TxUtilsConfig,
|
|
730
|
+
createVerificationJson: string | false = false,
|
|
436
731
|
) => {
|
|
437
732
|
const deployer = new L1Deployer(
|
|
438
733
|
extendedClient,
|
|
@@ -441,6 +736,7 @@ export const deployRollupForUpgrade = async (
|
|
|
441
736
|
args.acceleratedTestDeployments,
|
|
442
737
|
logger,
|
|
443
738
|
txUtilsConfig,
|
|
739
|
+
!!createVerificationJson,
|
|
444
740
|
);
|
|
445
741
|
|
|
446
742
|
const addresses = await RegistryContract.collectAddresses(extendedClient, registryAddress, 'canonical');
|
|
@@ -449,11 +745,17 @@ export const deployRollupForUpgrade = async (
|
|
|
449
745
|
|
|
450
746
|
await deployer.waitForDeployments();
|
|
451
747
|
|
|
748
|
+
// Write verification data (constructor args + linked libraries) to file for later forge verify
|
|
749
|
+
if (createVerificationJson) {
|
|
750
|
+
await generateRollupVerificationRecords(rollup, deployer, args, addresses, extendedClient, logger);
|
|
751
|
+
await writeVerificationJson(deployer, createVerificationJson, extendedClient.chain.id, 'upgrade', logger);
|
|
752
|
+
}
|
|
753
|
+
|
|
452
754
|
return { rollup, slashFactoryAddress };
|
|
453
755
|
};
|
|
454
756
|
|
|
455
757
|
export const deploySlashFactory = async (deployer: L1Deployer, rollupAddress: Hex, logger: Logger) => {
|
|
456
|
-
const slashFactoryAddress = await deployer.deploy(SlashFactoryArtifact, [rollupAddress]);
|
|
758
|
+
const slashFactoryAddress = (await deployer.deploy(SlashFactoryArtifact, [rollupAddress])).address;
|
|
457
759
|
logger.verbose(`Deployed SlashFactory at ${slashFactoryAddress}`);
|
|
458
760
|
return slashFactoryAddress;
|
|
459
761
|
};
|
|
@@ -462,10 +764,12 @@ export const deployUpgradePayload = async (
|
|
|
462
764
|
deployer: L1Deployer,
|
|
463
765
|
addresses: Pick<L1ContractAddresses, 'registryAddress' | 'rollupAddress'>,
|
|
464
766
|
) => {
|
|
465
|
-
const payloadAddress =
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
767
|
+
const payloadAddress = (
|
|
768
|
+
await deployer.deploy(RegisterNewRollupVersionPayloadArtifact, [
|
|
769
|
+
addresses.registryAddress.toString(),
|
|
770
|
+
addresses.rollupAddress.toString(),
|
|
771
|
+
])
|
|
772
|
+
).address;
|
|
469
773
|
|
|
470
774
|
return payloadAddress;
|
|
471
775
|
};
|
|
@@ -509,6 +813,7 @@ export const deployRollup = async (
|
|
|
509
813
|
if (!addresses.gseAddress) {
|
|
510
814
|
throw new Error('GSE address is required when deploying');
|
|
511
815
|
}
|
|
816
|
+
const networkName = getActiveNetworkName();
|
|
512
817
|
|
|
513
818
|
logger.info(`Deploying rollup using network configuration: ${networkName}`);
|
|
514
819
|
|
|
@@ -517,10 +822,10 @@ export const deployRollup = async (
|
|
|
517
822
|
let epochProofVerifier = EthAddress.ZERO;
|
|
518
823
|
|
|
519
824
|
if (args.realVerifier) {
|
|
520
|
-
epochProofVerifier = await deployer.deploy(l1ArtifactsVerifiers.honkVerifier);
|
|
825
|
+
epochProofVerifier = (await deployer.deploy(l1ArtifactsVerifiers.honkVerifier)).address;
|
|
521
826
|
logger.verbose(`Rollup will use the real verifier at ${epochProofVerifier}`);
|
|
522
827
|
} else {
|
|
523
|
-
epochProofVerifier = await deployer.deploy(mockVerifiers.mockVerifier);
|
|
828
|
+
epochProofVerifier = (await deployer.deploy(mockVerifiers.mockVerifier)).address;
|
|
524
829
|
logger.verbose(`Rollup will use the mock verifier at ${epochProofVerifier}`);
|
|
525
830
|
}
|
|
526
831
|
|
|
@@ -533,6 +838,7 @@ export const deployRollup = async (
|
|
|
533
838
|
aztecSlotDuration: BigInt(args.aztecSlotDuration),
|
|
534
839
|
aztecEpochDuration: BigInt(args.aztecEpochDuration),
|
|
535
840
|
targetCommitteeSize: BigInt(args.aztecTargetCommitteeSize),
|
|
841
|
+
lagInEpochs: BigInt(args.lagInEpochs),
|
|
536
842
|
aztecProofSubmissionEpochs: BigInt(args.aztecProofSubmissionEpochs),
|
|
537
843
|
slashingQuorum: BigInt(args.slashingQuorum ?? (args.slashingRoundSizeInEpochs * args.aztecEpochDuration) / 2 + 1),
|
|
538
844
|
slashingRoundSize: BigInt(args.slashingRoundSizeInEpochs * args.aztecEpochDuration),
|
|
@@ -543,17 +849,20 @@ export const deployRollup = async (
|
|
|
543
849
|
provingCostPerMana: args.provingCostPerMana,
|
|
544
850
|
rewardConfig: rewardConfig,
|
|
545
851
|
version: 0,
|
|
546
|
-
rewardBoostConfig: getRewardBoostConfig(
|
|
852
|
+
rewardBoostConfig: getRewardBoostConfig(),
|
|
547
853
|
stakingQueueConfig: getEntryQueueConfig(networkName),
|
|
548
854
|
exitDelaySeconds: BigInt(args.exitDelaySeconds),
|
|
549
855
|
slasherFlavor: slasherFlavorToSolidityEnum(args.slasherFlavor),
|
|
550
856
|
slashingOffsetInRounds: BigInt(args.slashingOffsetInRounds),
|
|
551
857
|
slashAmounts: [args.slashAmountSmall, args.slashAmountMedium, args.slashAmountLarge],
|
|
858
|
+
localEjectionThreshold: args.localEjectionThreshold,
|
|
859
|
+
slashingDisableDuration: BigInt(args.slashingDisableDuration ?? 0n),
|
|
860
|
+
earliestRewardsClaimableTimestamp: 0n,
|
|
552
861
|
};
|
|
553
862
|
|
|
554
863
|
const genesisStateArgs = {
|
|
555
864
|
vkTreeRoot: args.vkTreeRoot.toString(),
|
|
556
|
-
|
|
865
|
+
protocolContractsHash: args.protocolContractsHash.toString(),
|
|
557
866
|
genesisArchiveRoot: args.genesisArchiveRoot.toString(),
|
|
558
867
|
};
|
|
559
868
|
|
|
@@ -579,8 +888,10 @@ export const deployRollup = async (
|
|
|
579
888
|
rollupConfigArgs,
|
|
580
889
|
] as const;
|
|
581
890
|
|
|
582
|
-
const rollupAddress = await deployer.deploy(RollupArtifact, rollupArgs, {
|
|
583
|
-
|
|
891
|
+
const { address: rollupAddress, existed: rollupExisted } = await deployer.deploy(RollupArtifact, rollupArgs, {
|
|
892
|
+
gasLimit: 15_000_000n,
|
|
893
|
+
});
|
|
894
|
+
logger.verbose(`Deployed Rollup at ${rollupAddress}, already existed: ${rollupExisted}`, rollupConfigArgs);
|
|
584
895
|
|
|
585
896
|
const rollupContract = new RollupContract(extendedClient, rollupAddress);
|
|
586
897
|
|
|
@@ -588,24 +899,29 @@ export const deployRollup = async (
|
|
|
588
899
|
logger.verbose(`All core contracts have been deployed`);
|
|
589
900
|
|
|
590
901
|
if (args.feeJuicePortalInitialBalance && args.feeJuicePortalInitialBalance > 0n) {
|
|
591
|
-
|
|
902
|
+
// Skip funding when using an external token, as we likely don't have mint permissions
|
|
903
|
+
if (!('existingTokenAddress' in args) || !args.existingTokenAddress) {
|
|
904
|
+
const feeJuicePortalAddress = await rollupContract.getFeeJuicePortal();
|
|
592
905
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
906
|
+
// In fast mode, use the L1TxUtils to send transactions with nonce management
|
|
907
|
+
const { txHash: mintTxHash } = await deployer.sendTransaction({
|
|
908
|
+
to: addresses.feeJuiceAddress.toString(),
|
|
909
|
+
data: encodeFunctionData({
|
|
910
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
911
|
+
functionName: 'mint',
|
|
912
|
+
args: [feeJuicePortalAddress.toString(), args.feeJuicePortalInitialBalance],
|
|
913
|
+
}),
|
|
914
|
+
});
|
|
915
|
+
logger.verbose(
|
|
916
|
+
`Funding fee juice portal with ${args.feeJuicePortalInitialBalance} fee juice in ${mintTxHash} (accelerated test deployments)`,
|
|
917
|
+
);
|
|
918
|
+
txHashes.push(mintTxHash);
|
|
919
|
+
} else {
|
|
920
|
+
logger.verbose('Skipping fee juice portal funding due to external token usage');
|
|
921
|
+
}
|
|
606
922
|
}
|
|
607
923
|
|
|
608
|
-
const slashFactoryAddress = await deployer.deploy(SlashFactoryArtifact, [rollupAddress.toString()]);
|
|
924
|
+
const slashFactoryAddress = (await deployer.deploy(SlashFactoryArtifact, [rollupAddress.toString()])).address;
|
|
609
925
|
logger.verbose(`Deployed SlashFactory at ${slashFactoryAddress}`);
|
|
610
926
|
|
|
611
927
|
// We need to call a function on the registry to set the various contract addresses.
|
|
@@ -667,7 +983,17 @@ export const deployRollup = async (
|
|
|
667
983
|
logger.verbose(`Not the owner of the gse, skipping rollup addition`);
|
|
668
984
|
}
|
|
669
985
|
|
|
670
|
-
|
|
986
|
+
const activeAttestorCount = await rollupContract.getActiveAttesterCount();
|
|
987
|
+
const queuedAttestorCount = await rollupContract.getEntryQueueLength();
|
|
988
|
+
logger.info(`Rollup has ${activeAttestorCount} active attestors and ${queuedAttestorCount} queued attestors`);
|
|
989
|
+
|
|
990
|
+
const shouldAddValidators = activeAttestorCount === 0n && queuedAttestorCount === 0n;
|
|
991
|
+
|
|
992
|
+
if (
|
|
993
|
+
args.initialValidators &&
|
|
994
|
+
shouldAddValidators &&
|
|
995
|
+
(await gseContract.read.isRollupRegistered([rollupContract.address]))
|
|
996
|
+
) {
|
|
671
997
|
await addMultipleValidators(
|
|
672
998
|
extendedClient,
|
|
673
999
|
deployer,
|
|
@@ -715,6 +1041,7 @@ export const handoverToGovernance = async (
|
|
|
715
1041
|
governanceAddress: EthAddress,
|
|
716
1042
|
logger: Logger,
|
|
717
1043
|
acceleratedTestDeployments: boolean | undefined,
|
|
1044
|
+
useExternalToken: boolean = false,
|
|
718
1045
|
) => {
|
|
719
1046
|
// We need to call a function on the registry to set the various contract addresses.
|
|
720
1047
|
const registryContract = getContract({
|
|
@@ -780,7 +1107,10 @@ export const handoverToGovernance = async (
|
|
|
780
1107
|
txHashes.push(transferOwnershipTxHash);
|
|
781
1108
|
}
|
|
782
1109
|
|
|
783
|
-
if (
|
|
1110
|
+
if (
|
|
1111
|
+
!useExternalToken &&
|
|
1112
|
+
(acceleratedTestDeployments || (await feeAsset.read.owner()) !== coinIssuerAddress.toString())
|
|
1113
|
+
) {
|
|
784
1114
|
const { txHash } = await deployer.sendTransaction(
|
|
785
1115
|
{
|
|
786
1116
|
to: feeAssetAddress.toString(),
|
|
@@ -807,23 +1137,28 @@ export const handoverToGovernance = async (
|
|
|
807
1137
|
);
|
|
808
1138
|
logger.verbose(`Accept ownership of fee asset in ${acceptTokenOwnershipTxHash}`);
|
|
809
1139
|
txHashes.push(acceptTokenOwnershipTxHash);
|
|
1140
|
+
} else if (useExternalToken) {
|
|
1141
|
+
logger.verbose('Skipping fee asset ownership transfer due to external token usage');
|
|
810
1142
|
}
|
|
811
1143
|
|
|
1144
|
+
// Either deploy or at least predict the address of the date gated relayer
|
|
1145
|
+
const dateGatedRelayer = await deployer.deploy(DateGatedRelayerArtifact, [
|
|
1146
|
+
governanceAddress.toString(),
|
|
1147
|
+
1798761600n, // 2027-01-01 00:00:00 UTC
|
|
1148
|
+
]);
|
|
1149
|
+
|
|
812
1150
|
// If the owner is not the Governance contract, transfer ownership to the Governance contract
|
|
813
|
-
if (
|
|
814
|
-
acceleratedTestDeployments ||
|
|
815
|
-
(await coinIssuerContract.read.owner()) !== getAddress(governanceAddress.toString())
|
|
816
|
-
) {
|
|
1151
|
+
if (acceleratedTestDeployments || (await coinIssuerContract.read.owner()) === deployer.client.account.address) {
|
|
817
1152
|
const { txHash: transferOwnershipTxHash } = await deployer.sendTransaction({
|
|
818
1153
|
to: coinIssuerContract.address,
|
|
819
1154
|
data: encodeFunctionData({
|
|
820
1155
|
abi: CoinIssuerArtifact.contractAbi,
|
|
821
1156
|
functionName: 'transferOwnership',
|
|
822
|
-
args: [getAddress(
|
|
1157
|
+
args: [getAddress(dateGatedRelayer.address.toString())],
|
|
823
1158
|
}),
|
|
824
1159
|
});
|
|
825
1160
|
logger.verbose(
|
|
826
|
-
`Transferring the ownership of the coin issuer contract at ${coinIssuerAddress} to the
|
|
1161
|
+
`Transferring the ownership of the coin issuer contract at ${coinIssuerAddress} to the DateGatedRelayer ${dateGatedRelayer.address} in tx ${transferOwnershipTxHash}`,
|
|
827
1162
|
);
|
|
828
1163
|
txHashes.push(transferOwnershipTxHash);
|
|
829
1164
|
}
|
|
@@ -831,6 +1166,8 @@ export const handoverToGovernance = async (
|
|
|
831
1166
|
// Wait for all actions to be mined
|
|
832
1167
|
await deployer.waitForDeployments();
|
|
833
1168
|
await Promise.all(txHashes.map(txHash => extendedClient.waitForTransactionReceipt({ hash: txHash })));
|
|
1169
|
+
|
|
1170
|
+
return { dateGatedRelayerAddress: dateGatedRelayer.address };
|
|
834
1171
|
};
|
|
835
1172
|
|
|
836
1173
|
/*
|
|
@@ -877,100 +1214,112 @@ export const addMultipleValidators = async (
|
|
|
877
1214
|
validators = enrichedValidators.filter(v => v.status === 0).map(v => v.operator);
|
|
878
1215
|
}
|
|
879
1216
|
|
|
880
|
-
if (validators.length
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1217
|
+
if (validators.length === 0) {
|
|
1218
|
+
logger.warn('No validators to add. Skipping.');
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
const gseContract = new GSEContract(extendedClient, gseAddress);
|
|
1223
|
+
const multiAdder = (await deployer.deploy(MultiAdderArtifact, [rollupAddress, deployer.client.account.address]))
|
|
1224
|
+
.address;
|
|
1225
|
+
|
|
1226
|
+
const makeValidatorTuples = async (validator: Operator) => {
|
|
1227
|
+
const registrationTuple = await gseContract.makeRegistrationTuple(validator.bn254SecretKey.getValue());
|
|
1228
|
+
return {
|
|
1229
|
+
attester: getAddress(validator.attester.toString()),
|
|
1230
|
+
withdrawer: getAddress(validator.withdrawer.toString()),
|
|
1231
|
+
...registrationTuple,
|
|
891
1232
|
};
|
|
1233
|
+
};
|
|
892
1234
|
|
|
893
|
-
|
|
1235
|
+
const validatorsTuples = await Promise.all(validators.map(makeValidatorTuples));
|
|
894
1236
|
|
|
895
|
-
|
|
896
|
-
|
|
1237
|
+
// Mint tokens, approve them, use cheat code to initialize validator set without setting up the epoch.
|
|
1238
|
+
const stakeNeeded = activationThreshold * BigInt(validators.length);
|
|
897
1239
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1240
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction({
|
|
1241
|
+
to: stakingAssetAddress,
|
|
1242
|
+
data: encodeFunctionData({
|
|
1243
|
+
abi: StakingAssetArtifact.contractAbi,
|
|
1244
|
+
functionName: 'mint',
|
|
1245
|
+
args: [multiAdder.toString(), stakeNeeded],
|
|
1246
|
+
}),
|
|
1247
|
+
});
|
|
906
1248
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
logger.info(`Adding ${validators.length} validators to the rollup`);
|
|
911
|
-
|
|
912
|
-
// Adding to the queue and flushing need to be done in two transactions
|
|
913
|
-
// if we are adding many validators.
|
|
914
|
-
if (validatorsTuples.length > 10) {
|
|
915
|
-
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
916
|
-
{
|
|
917
|
-
to: multiAdder.toString(),
|
|
918
|
-
data: encodeFunctionData({
|
|
919
|
-
abi: MultiAdderArtifact.contractAbi,
|
|
920
|
-
functionName: 'addValidators',
|
|
921
|
-
args: [validatorsTuples, true],
|
|
922
|
-
}),
|
|
923
|
-
},
|
|
924
|
-
{
|
|
925
|
-
gasLimit: 40_000_000n,
|
|
926
|
-
},
|
|
927
|
-
);
|
|
1249
|
+
const entryQueueLengthBefore = await rollup.getEntryQueueLength();
|
|
1250
|
+
const validatorCountBefore = await rollup.getActiveAttesterCount();
|
|
928
1251
|
|
|
929
|
-
|
|
930
|
-
{
|
|
931
|
-
to: rollupAddress,
|
|
932
|
-
data: encodeFunctionData({
|
|
933
|
-
abi: RollupArtifact.contractAbi,
|
|
934
|
-
functionName: 'flushEntryQueue',
|
|
935
|
-
args: [],
|
|
936
|
-
}),
|
|
937
|
-
},
|
|
938
|
-
{
|
|
939
|
-
gasLimit: 40_000_000n,
|
|
940
|
-
},
|
|
941
|
-
);
|
|
942
|
-
} else {
|
|
943
|
-
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
944
|
-
{
|
|
945
|
-
to: multiAdder.toString(),
|
|
946
|
-
data: encodeFunctionData({
|
|
947
|
-
abi: MultiAdderArtifact.contractAbi,
|
|
948
|
-
functionName: 'addValidators',
|
|
949
|
-
args: [validatorsTuples, false],
|
|
950
|
-
}),
|
|
951
|
-
},
|
|
952
|
-
{
|
|
953
|
-
gasLimit: 45_000_000n,
|
|
954
|
-
},
|
|
955
|
-
);
|
|
956
|
-
}
|
|
1252
|
+
logger.info(`Adding ${validators.length} validators to the rollup`);
|
|
957
1253
|
|
|
958
|
-
|
|
959
|
-
const validatorCountAfter = await rollup.getActiveAttesterCount();
|
|
1254
|
+
const chunkSize = 16;
|
|
960
1255
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1256
|
+
// We will add `chunkSize` validators to the queue until we have covered all of our validators.
|
|
1257
|
+
// The `chunkSize` needs to be small enough to fit inside a single tx, therefore 16.
|
|
1258
|
+
for (const c of chunk(validatorsTuples, chunkSize)) {
|
|
1259
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
1260
|
+
{
|
|
1261
|
+
to: multiAdder.toString(),
|
|
1262
|
+
data: encodeFunctionData({
|
|
1263
|
+
abi: MultiAdderArtifact.contractAbi,
|
|
1264
|
+
functionName: 'addValidators',
|
|
1265
|
+
args: [c, BigInt(0)],
|
|
1266
|
+
}),
|
|
1267
|
+
},
|
|
1268
|
+
{
|
|
1269
|
+
gasLimit: 16_000_000n,
|
|
1270
|
+
},
|
|
1271
|
+
);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
// After adding to the queue, we will now try to flush from it.
|
|
1275
|
+
// We are explicitly doing this as a second step instead of as part of adding to benefit
|
|
1276
|
+
// from the accounting used to speed the process up.
|
|
1277
|
+
// As the queue computes the amount of possible flushes in an epoch when told to flush,
|
|
1278
|
+
// waiting until we have added all we want allows us to benefit in the case were we added
|
|
1279
|
+
// enough to pass the bootstrap set size without needing to wait another epoch.
|
|
1280
|
+
// This is useful when we are testing as it speeds up the tests slightly.
|
|
1281
|
+
while (true) {
|
|
1282
|
+
// If the queue is empty, we can break
|
|
1283
|
+
if ((await rollup.getEntryQueueLength()) == 0n) {
|
|
1284
|
+
break;
|
|
968
1285
|
}
|
|
969
1286
|
|
|
970
|
-
|
|
971
|
-
|
|
1287
|
+
// If there are no available validator flushes, no need to even try
|
|
1288
|
+
if ((await rollup.getAvailableValidatorFlushes()) == 0n) {
|
|
1289
|
+
break;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
// Note that we are flushing at most `chunkSize` at each call
|
|
1293
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
1294
|
+
{
|
|
1295
|
+
to: rollup.address,
|
|
1296
|
+
data: encodeFunctionData({
|
|
1297
|
+
abi: RollupArtifact.contractAbi,
|
|
1298
|
+
functionName: 'flushEntryQueue',
|
|
1299
|
+
args: [BigInt(chunkSize)],
|
|
1300
|
+
}),
|
|
1301
|
+
},
|
|
1302
|
+
{
|
|
1303
|
+
gasLimit: 16_000_000n,
|
|
1304
|
+
},
|
|
972
1305
|
);
|
|
973
1306
|
}
|
|
1307
|
+
|
|
1308
|
+
const entryQueueLengthAfter = await rollup.getEntryQueueLength();
|
|
1309
|
+
const validatorCountAfter = await rollup.getActiveAttesterCount();
|
|
1310
|
+
|
|
1311
|
+
if (
|
|
1312
|
+
entryQueueLengthAfter + validatorCountAfter <
|
|
1313
|
+
entryQueueLengthBefore + validatorCountBefore + BigInt(validators.length)
|
|
1314
|
+
) {
|
|
1315
|
+
throw new Error(
|
|
1316
|
+
`Failed to add ${validators.length} validators. Active validators: ${validatorCountBefore} -> ${validatorCountAfter}. Queue: ${entryQueueLengthBefore} -> ${entryQueueLengthAfter}. A likely issue is the bootstrap size.`,
|
|
1317
|
+
);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
logger.info(
|
|
1321
|
+
`Added ${validators.length} validators. Active validators: ${validatorCountBefore} -> ${validatorCountAfter}. Queue: ${entryQueueLengthBefore} -> ${entryQueueLengthAfter}`,
|
|
1322
|
+
);
|
|
974
1323
|
}
|
|
975
1324
|
};
|
|
976
1325
|
|
|
@@ -993,11 +1342,13 @@ export const cheat_initializeFeeAssetHandler = async (
|
|
|
993
1342
|
feeAssetHandlerAddress: EthAddress;
|
|
994
1343
|
txHash: Hex;
|
|
995
1344
|
}> => {
|
|
996
|
-
const feeAssetHandlerAddress =
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1345
|
+
const feeAssetHandlerAddress = (
|
|
1346
|
+
await deployer.deploy(FeeAssetHandlerArtifact, [
|
|
1347
|
+
extendedClient.account.address,
|
|
1348
|
+
feeAssetAddress.toString(),
|
|
1349
|
+
BigInt(1e18),
|
|
1350
|
+
])
|
|
1351
|
+
).address;
|
|
1001
1352
|
logger.verbose(`Deployed FeeAssetHandler at ${feeAssetHandlerAddress}`);
|
|
1002
1353
|
|
|
1003
1354
|
const { txHash } = await deployer.sendTransaction({
|
|
@@ -1033,6 +1384,13 @@ export const deployL1Contracts = async (
|
|
|
1033
1384
|
logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`);
|
|
1034
1385
|
validateConfig(args);
|
|
1035
1386
|
|
|
1387
|
+
if (args.initialValidators && args.initialValidators.length > 0 && args.existingTokenAddress) {
|
|
1388
|
+
throw new Error(
|
|
1389
|
+
'Cannot deploy with both initialValidators and existingTokenAddress. ' +
|
|
1390
|
+
'Initial validator funding requires minting tokens, which is not possible with an external token.',
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1036
1394
|
const l1Client = createExtendedL1Client(rpcUrls, account, chain);
|
|
1037
1395
|
|
|
1038
1396
|
// Deploy multicall3 if it does not exist in this network
|
|
@@ -1102,7 +1460,7 @@ export const deployL1Contracts = async (
|
|
|
1102
1460
|
await deployer.waitForDeployments();
|
|
1103
1461
|
|
|
1104
1462
|
// Now that the rollup has been deployed and added to the registry, transfer ownership to governance
|
|
1105
|
-
await handoverToGovernance(
|
|
1463
|
+
const { dateGatedRelayerAddress } = await handoverToGovernance(
|
|
1106
1464
|
l1Client,
|
|
1107
1465
|
deployer,
|
|
1108
1466
|
registryAddress,
|
|
@@ -1112,6 +1470,7 @@ export const deployL1Contracts = async (
|
|
|
1112
1470
|
governanceAddress,
|
|
1113
1471
|
logger,
|
|
1114
1472
|
args.acceleratedTestDeployments,
|
|
1473
|
+
!!args.existingTokenAddress,
|
|
1115
1474
|
);
|
|
1116
1475
|
|
|
1117
1476
|
logger.info(`Handing over to governance complete`);
|
|
@@ -1123,143 +1482,8 @@ export const deployL1Contracts = async (
|
|
|
1123
1482
|
|
|
1124
1483
|
// Write verification data (constructor args + linked libraries) to file for later forge verify
|
|
1125
1484
|
if (createVerificationJson) {
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
const rollupAddr = l1Contracts.rollupAddress.toString();
|
|
1129
|
-
const inboxAddr = l1Contracts.inboxAddress.toString();
|
|
1130
|
-
const outboxAddr = l1Contracts.outboxAddress.toString();
|
|
1131
|
-
const feeAsset = l1Contracts.feeJuiceAddress.toString();
|
|
1132
|
-
const version = await rollup.getVersion();
|
|
1133
|
-
|
|
1134
|
-
const inboxCtor = encodeAbiParameters(
|
|
1135
|
-
[{ type: 'address' }, { type: 'address' }, { type: 'uint256' }, { type: 'uint256' }],
|
|
1136
|
-
[rollupAddr, feeAsset, version, BigInt(L1_TO_L2_MSG_SUBTREE_HEIGHT)],
|
|
1137
|
-
);
|
|
1138
|
-
|
|
1139
|
-
const outboxCtor = encodeAbiParameters([{ type: 'address' }, { type: 'uint256' }], [rollupAddr, version]);
|
|
1140
|
-
|
|
1141
|
-
deployer.verificationRecords.push(
|
|
1142
|
-
{ name: 'Inbox', address: inboxAddr, constructorArgsHex: inboxCtor, libraries: [] },
|
|
1143
|
-
{ name: 'Outbox', address: outboxAddr, constructorArgsHex: outboxCtor, libraries: [] },
|
|
1144
|
-
);
|
|
1145
|
-
|
|
1146
|
-
// Include Slasher and SlashingProposer (if deployed) in verification data
|
|
1147
|
-
try {
|
|
1148
|
-
const slasherAddrHex = await rollup.getSlasher();
|
|
1149
|
-
const slasherAddr = EthAddress.fromString(slasherAddrHex);
|
|
1150
|
-
if (!slasherAddr.isZero()) {
|
|
1151
|
-
// Slasher constructor: (address _vetoer, address _governance)
|
|
1152
|
-
const slasherCtor = encodeAbiParameters(
|
|
1153
|
-
[{ type: 'address' }, { type: 'address' }],
|
|
1154
|
-
[args.slashingVetoer.toString(), l1Client.account.address],
|
|
1155
|
-
);
|
|
1156
|
-
deployer.verificationRecords.push({
|
|
1157
|
-
name: 'Slasher',
|
|
1158
|
-
address: slasherAddr.toString(),
|
|
1159
|
-
constructorArgsHex: slasherCtor,
|
|
1160
|
-
libraries: [],
|
|
1161
|
-
});
|
|
1162
|
-
|
|
1163
|
-
// Proposer address is stored in Slasher.PROPOSER()
|
|
1164
|
-
const proposerAddr = (await rollup.getSlashingProposerAddress()).toString();
|
|
1165
|
-
|
|
1166
|
-
// Compute constructor args matching deployment path in RollupCore
|
|
1167
|
-
const computedRoundSize = BigInt(args.slashingRoundSizeInEpochs * args.aztecEpochDuration);
|
|
1168
|
-
const computedQuorum = BigInt(
|
|
1169
|
-
args.slashingQuorum ?? (args.slashingRoundSizeInEpochs * args.aztecEpochDuration) / 2 + 1,
|
|
1170
|
-
);
|
|
1171
|
-
const lifetimeInRounds = BigInt(args.slashingLifetimeInRounds);
|
|
1172
|
-
const executionDelayInRounds = BigInt(args.slashingExecutionDelayInRounds);
|
|
1173
|
-
|
|
1174
|
-
if (args.slasherFlavor === 'tally') {
|
|
1175
|
-
const slashAmounts: readonly [bigint, bigint, bigint] = [
|
|
1176
|
-
args.slashAmountSmall,
|
|
1177
|
-
args.slashAmountMedium,
|
|
1178
|
-
args.slashAmountLarge,
|
|
1179
|
-
];
|
|
1180
|
-
const committeeSize = BigInt(args.aztecTargetCommitteeSize);
|
|
1181
|
-
const epochDuration = BigInt(args.aztecEpochDuration);
|
|
1182
|
-
const slashOffsetInRounds = BigInt(args.slashingOffsetInRounds);
|
|
1183
|
-
|
|
1184
|
-
const proposerCtor = encodeAbiParameters(
|
|
1185
|
-
[
|
|
1186
|
-
{ type: 'address' },
|
|
1187
|
-
{ type: 'address' },
|
|
1188
|
-
{ type: 'uint256' },
|
|
1189
|
-
{ type: 'uint256' },
|
|
1190
|
-
{ type: 'uint256' },
|
|
1191
|
-
{ type: 'uint256' },
|
|
1192
|
-
{ type: 'uint256[3]' },
|
|
1193
|
-
{ type: 'uint256' },
|
|
1194
|
-
{ type: 'uint256' },
|
|
1195
|
-
{ type: 'uint256' },
|
|
1196
|
-
],
|
|
1197
|
-
[
|
|
1198
|
-
rollup.address,
|
|
1199
|
-
slasherAddr.toString(),
|
|
1200
|
-
computedQuorum,
|
|
1201
|
-
computedRoundSize,
|
|
1202
|
-
lifetimeInRounds,
|
|
1203
|
-
executionDelayInRounds,
|
|
1204
|
-
slashAmounts,
|
|
1205
|
-
committeeSize,
|
|
1206
|
-
epochDuration,
|
|
1207
|
-
slashOffsetInRounds,
|
|
1208
|
-
],
|
|
1209
|
-
);
|
|
1210
|
-
|
|
1211
|
-
deployer.verificationRecords.push({
|
|
1212
|
-
name: 'TallySlashingProposer',
|
|
1213
|
-
address: proposerAddr,
|
|
1214
|
-
constructorArgsHex: proposerCtor,
|
|
1215
|
-
libraries: [],
|
|
1216
|
-
});
|
|
1217
|
-
} else if (args.slasherFlavor === 'empire') {
|
|
1218
|
-
const proposerCtor = encodeAbiParameters(
|
|
1219
|
-
[
|
|
1220
|
-
{ type: 'address' },
|
|
1221
|
-
{ type: 'address' },
|
|
1222
|
-
{ type: 'uint256' },
|
|
1223
|
-
{ type: 'uint256' },
|
|
1224
|
-
{ type: 'uint256' },
|
|
1225
|
-
{ type: 'uint256' },
|
|
1226
|
-
],
|
|
1227
|
-
[
|
|
1228
|
-
rollup.address,
|
|
1229
|
-
slasherAddr.toString(),
|
|
1230
|
-
computedQuorum,
|
|
1231
|
-
computedRoundSize,
|
|
1232
|
-
lifetimeInRounds,
|
|
1233
|
-
executionDelayInRounds,
|
|
1234
|
-
],
|
|
1235
|
-
);
|
|
1236
|
-
|
|
1237
|
-
deployer.verificationRecords.push({
|
|
1238
|
-
name: 'EmpireSlashingProposer',
|
|
1239
|
-
address: proposerAddr,
|
|
1240
|
-
constructorArgsHex: proposerCtor,
|
|
1241
|
-
libraries: [],
|
|
1242
|
-
});
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
} catch (e) {
|
|
1246
|
-
logger.warn(`Failed to add Slasher/Proposer verification records: ${String(e)}`);
|
|
1247
|
-
}
|
|
1248
|
-
const date = new Date();
|
|
1249
|
-
const formattedDate = date.toISOString().slice(2, 19).replace(/[-T:]/g, '');
|
|
1250
|
-
// Ensure the verification output directory exists
|
|
1251
|
-
await mkdir(createVerificationJson, { recursive: true });
|
|
1252
|
-
const verificationOutputPath = `${createVerificationJson}/l1-verify-${chain.id}-${formattedDate.slice(0, 6)}-${formattedDate.slice(6)}.json`;
|
|
1253
|
-
const verificationData = {
|
|
1254
|
-
chainId: chain.id,
|
|
1255
|
-
network: networkName,
|
|
1256
|
-
records: deployer.verificationRecords,
|
|
1257
|
-
};
|
|
1258
|
-
await writeFile(verificationOutputPath, JSON.stringify(verificationData, null, 2));
|
|
1259
|
-
logger.info(`Wrote L1 verification data to ${verificationOutputPath}`);
|
|
1260
|
-
} catch (e) {
|
|
1261
|
-
logger.warn(`Failed to write L1 verification data file: ${String(e)}`);
|
|
1262
|
-
}
|
|
1485
|
+
await generateRollupVerificationRecords(rollup, deployer, args, l1Contracts, l1Client, logger);
|
|
1486
|
+
await writeVerificationJson(deployer, createVerificationJson, chain.id, '', logger);
|
|
1263
1487
|
}
|
|
1264
1488
|
|
|
1265
1489
|
if (isAnvilTestChain(chain.id)) {
|
|
@@ -1295,6 +1519,7 @@ export const deployL1Contracts = async (
|
|
|
1295
1519
|
stakingAssetHandlerAddress,
|
|
1296
1520
|
zkPassportVerifierAddress,
|
|
1297
1521
|
coinIssuerAddress,
|
|
1522
|
+
dateGatedRelayerAddress,
|
|
1298
1523
|
},
|
|
1299
1524
|
};
|
|
1300
1525
|
};
|
|
@@ -1317,10 +1542,8 @@ export class L1Deployer {
|
|
|
1317
1542
|
this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), { size: 32 }) : undefined;
|
|
1318
1543
|
this.l1TxUtils = createL1TxUtilsFromViemWallet(
|
|
1319
1544
|
this.client,
|
|
1320
|
-
this.logger,
|
|
1321
|
-
|
|
1322
|
-
this.txUtilsConfig,
|
|
1323
|
-
this.acceleratedTestDeployments,
|
|
1545
|
+
{ logger: this.logger, dateProvider },
|
|
1546
|
+
{ ...this.txUtilsConfig, debugMaxGasLimit: acceleratedTestDeployments },
|
|
1324
1547
|
);
|
|
1325
1548
|
}
|
|
1326
1549
|
|
|
@@ -1328,10 +1551,10 @@ export class L1Deployer {
|
|
|
1328
1551
|
params: ContractArtifacts<TAbi>,
|
|
1329
1552
|
args?: ContractConstructorArgs<TAbi>,
|
|
1330
1553
|
opts: { gasLimit?: bigint } = {},
|
|
1331
|
-
): Promise<EthAddress> {
|
|
1554
|
+
): Promise<{ address: EthAddress; existed: boolean }> {
|
|
1332
1555
|
this.logger.debug(`Deploying ${params.name} contract`, { args });
|
|
1333
1556
|
try {
|
|
1334
|
-
const { txHash, address, deployedLibraries } = await deployL1Contract(
|
|
1557
|
+
const { txHash, address, deployedLibraries, existed } = await deployL1Contract(
|
|
1335
1558
|
this.client,
|
|
1336
1559
|
params.contractAbi,
|
|
1337
1560
|
params.contractBytecode,
|
|
@@ -1369,7 +1592,10 @@ export class L1Deployer {
|
|
|
1369
1592
|
libraries: deployedLibraries ?? [],
|
|
1370
1593
|
});
|
|
1371
1594
|
}
|
|
1372
|
-
return
|
|
1595
|
+
return {
|
|
1596
|
+
address,
|
|
1597
|
+
existed,
|
|
1598
|
+
};
|
|
1373
1599
|
} catch (error) {
|
|
1374
1600
|
throw new Error(`Failed to deploy ${params.name}`, { cause: formatViemError(error) });
|
|
1375
1601
|
}
|
|
@@ -1397,13 +1623,16 @@ export class L1Deployer {
|
|
|
1397
1623
|
|
|
1398
1624
|
sendTransaction(
|
|
1399
1625
|
tx: L1TxRequest,
|
|
1400
|
-
options?:
|
|
1626
|
+
options?: L1TxConfig,
|
|
1401
1627
|
): Promise<{ txHash: Hex; gasLimit: bigint; gasPrice: GasPrice }> {
|
|
1402
|
-
return this.l1TxUtils.sendTransaction(tx, options)
|
|
1628
|
+
return this.l1TxUtils.sendTransaction(tx, options).then(({ txHash, state }) => ({
|
|
1629
|
+
txHash,
|
|
1630
|
+
gasLimit: state.gasLimit,
|
|
1631
|
+
gasPrice: state.gasPrice,
|
|
1632
|
+
}));
|
|
1403
1633
|
}
|
|
1404
1634
|
}
|
|
1405
1635
|
|
|
1406
|
-
// docs:start:deployL1Contract
|
|
1407
1636
|
/**
|
|
1408
1637
|
* Helper function to deploy ETH contracts.
|
|
1409
1638
|
* @param walletClient - A viem WalletClient.
|
|
@@ -1427,7 +1656,12 @@ export async function deployL1Contract(
|
|
|
1427
1656
|
gasLimit?: bigint;
|
|
1428
1657
|
acceleratedTestDeployments?: boolean;
|
|
1429
1658
|
} = {},
|
|
1430
|
-
): Promise<{
|
|
1659
|
+
): Promise<{
|
|
1660
|
+
address: EthAddress;
|
|
1661
|
+
txHash: Hex | undefined;
|
|
1662
|
+
deployedLibraries?: VerificationLibraryEntry[];
|
|
1663
|
+
existed: boolean;
|
|
1664
|
+
}> {
|
|
1431
1665
|
let txHash: Hex | undefined = undefined;
|
|
1432
1666
|
let resultingAddress: Hex | null | undefined = undefined;
|
|
1433
1667
|
const deployedLibraries: VerificationLibraryEntry[] = [];
|
|
@@ -1437,7 +1671,11 @@ export async function deployL1Contract(
|
|
|
1437
1671
|
|
|
1438
1672
|
if (!l1TxUtils) {
|
|
1439
1673
|
const config = getL1TxUtilsConfigEnvVars();
|
|
1440
|
-
l1TxUtils = createL1TxUtilsFromViemWallet(
|
|
1674
|
+
l1TxUtils = createL1TxUtilsFromViemWallet(
|
|
1675
|
+
extendedClient,
|
|
1676
|
+
{ logger },
|
|
1677
|
+
{ ...config, debugMaxGasLimit: acceleratedTestDeployments },
|
|
1678
|
+
);
|
|
1441
1679
|
}
|
|
1442
1680
|
|
|
1443
1681
|
if (libraries) {
|
|
@@ -1529,6 +1767,8 @@ export async function deployL1Contract(
|
|
|
1529
1767
|
}
|
|
1530
1768
|
}
|
|
1531
1769
|
|
|
1770
|
+
let existed = false;
|
|
1771
|
+
|
|
1532
1772
|
if (saltFromOpts) {
|
|
1533
1773
|
logger?.info(`Deploying contract with salt ${saltFromOpts}`);
|
|
1534
1774
|
const { address, paddedSalt: salt, calldata } = getExpectedAddress(abi, bytecode, args, saltFromOpts);
|
|
@@ -1536,10 +1776,10 @@ export async function deployL1Contract(
|
|
|
1536
1776
|
const existing = await extendedClient.getCode({ address: resultingAddress });
|
|
1537
1777
|
if (existing === undefined || existing === '0x') {
|
|
1538
1778
|
try {
|
|
1539
|
-
await l1TxUtils.simulate({ to: DEPLOYER_ADDRESS, data: concatHex([salt, calldata])
|
|
1779
|
+
await l1TxUtils.simulate({ to: DEPLOYER_ADDRESS, data: concatHex([salt, calldata]), gas: gasLimit });
|
|
1540
1780
|
} catch (err) {
|
|
1541
1781
|
logger?.error(`Failed to simulate deployment tx using universal deployer`, err);
|
|
1542
|
-
await l1TxUtils.simulate({ to: null, data: encodeDeployData({ abi, bytecode, args }) });
|
|
1782
|
+
await l1TxUtils.simulate({ to: null, data: encodeDeployData({ abi, bytecode, args }), gas: gasLimit });
|
|
1543
1783
|
}
|
|
1544
1784
|
const res = await l1TxUtils.sendTransaction(
|
|
1545
1785
|
{ to: DEPLOYER_ADDRESS, data: concatHex([salt, calldata]) },
|
|
@@ -1550,13 +1790,17 @@ export async function deployL1Contract(
|
|
|
1550
1790
|
logger?.verbose(`Deployed contract with salt ${salt} to address ${resultingAddress} in tx ${txHash}.`);
|
|
1551
1791
|
} else {
|
|
1552
1792
|
logger?.verbose(`Skipping existing deployment of contract with salt ${salt} to address ${resultingAddress}`);
|
|
1793
|
+
existed = true;
|
|
1553
1794
|
}
|
|
1554
1795
|
} else {
|
|
1555
1796
|
const deployData = encodeDeployData({ abi, bytecode, args });
|
|
1556
|
-
const { receipt } = await l1TxUtils.sendAndMonitorTransaction(
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1797
|
+
const { receipt } = await l1TxUtils.sendAndMonitorTransaction(
|
|
1798
|
+
{
|
|
1799
|
+
to: null,
|
|
1800
|
+
data: deployData,
|
|
1801
|
+
},
|
|
1802
|
+
{ gasLimit },
|
|
1803
|
+
);
|
|
1560
1804
|
|
|
1561
1805
|
txHash = receipt.transactionHash;
|
|
1562
1806
|
resultingAddress = receipt.contractAddress;
|
|
@@ -1569,7 +1813,7 @@ export async function deployL1Contract(
|
|
|
1569
1813
|
}
|
|
1570
1814
|
}
|
|
1571
1815
|
|
|
1572
|
-
return { address: EthAddress.fromString(resultingAddress!), txHash, deployedLibraries };
|
|
1816
|
+
return { address: EthAddress.fromString(resultingAddress!), txHash, deployedLibraries, existed };
|
|
1573
1817
|
}
|
|
1574
1818
|
|
|
1575
1819
|
export function getExpectedAddress(
|
|
@@ -1592,5 +1836,3 @@ export function getExpectedAddress(
|
|
|
1592
1836
|
calldata,
|
|
1593
1837
|
};
|
|
1594
1838
|
}
|
|
1595
|
-
|
|
1596
|
-
// docs:end:deployL1Contract
|