@aztec/ethereum 3.0.0-canary.a9708bd → 3.0.0-devnet.20251212
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/account.d.ts +1 -1
- package/dest/chain.d.ts +1 -1
- package/dest/client.d.ts +2 -2
- package/dest/client.d.ts.map +1 -1
- package/dest/config.d.ts +16 -8
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +160 -62
- package/dest/constants.d.ts +1 -1
- package/dest/contracts/empire_base.d.ts +7 -6
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/empire_base.js +1 -1
- package/dest/contracts/empire_slashing_proposer.d.ts +7 -6
- package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.js +9 -3
- package/dest/contracts/errors.d.ts +1 -1
- package/dest/contracts/errors.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.d.ts +4 -4
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
- package/dest/contracts/fee_juice.d.ts +1 -1
- package/dest/contracts/fee_juice.d.ts.map +1 -1
- package/dest/contracts/governance.d.ts +16 -16
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +7 -3
- package/dest/contracts/governance_proposer.d.ts +6 -6
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +9 -4
- package/dest/contracts/gse.d.ts +1 -1
- package/dest/contracts/gse.d.ts.map +1 -1
- package/dest/contracts/inbox.d.ts +1 -1
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/index.d.ts +1 -1
- package/dest/contracts/multicall.d.ts +5 -7
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +6 -4
- package/dest/contracts/registry.d.ts +1 -1
- package/dest/contracts/registry.d.ts.map +1 -1
- package/dest/contracts/rollup.d.ts +83 -72
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +144 -139
- package/dest/contracts/slasher_contract.d.ts +11 -1
- 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 +30 -9
- package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/tally_slashing_proposer.js +58 -8
- package/dest/contracts/utils.d.ts +1 -1
- package/dest/deploy_l1_contracts.d.ts +477 -15
- package/dest/deploy_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_l1_contracts.js +610 -386
- package/dest/eth-signer/eth-signer.d.ts +1 -1
- package/dest/eth-signer/index.d.ts +1 -1
- package/dest/forwarder_proxy.d.ts +32 -0
- package/dest/forwarder_proxy.d.ts.map +1 -0
- package/dest/forwarder_proxy.js +93 -0
- package/dest/l1_artifacts.d.ts +14258 -6015
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +10 -5
- package/dest/l1_contract_addresses.d.ts +8 -4
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +16 -26
- package/dest/l1_reader.d.ts +4 -2
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +14 -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 +96 -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/forwarder_l1_tx_utils.d.ts +41 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +48 -0
- package/dest/l1_tx_utils/index-blobs.d.ts +3 -0
- package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -0
- package/dest/l1_tx_utils/index-blobs.js +2 -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 +94 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/l1_tx_utils.js +623 -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 +94 -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 +431 -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/l1_types.d.ts +1 -1
- package/dest/publisher_manager.d.ts +8 -3
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +36 -8
- package/dest/queries.d.ts +1 -1
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +13 -12
- package/dest/test/chain_monitor.d.ts +33 -19
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +100 -33
- package/dest/test/delayed_tx_utils.d.ts +3 -3
- 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 +36 -14
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +124 -31
- package/dest/test/eth_cheat_codes_with_state.d.ts +1 -1
- package/dest/test/eth_cheat_codes_with_state.d.ts.map +1 -1
- package/dest/test/index.d.ts +1 -1
- package/dest/test/rollup_cheat_codes.d.ts +23 -20
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +79 -42
- package/dest/test/start_anvil.d.ts +2 -1
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +2 -1
- package/dest/test/tx_delayer.d.ts +1 -1
- package/dest/test/tx_delayer.d.ts.map +1 -1
- package/dest/test/tx_delayer.js +3 -2
- package/dest/test/upgrade_utils.d.ts +1 -1
- package/dest/test/upgrade_utils.d.ts.map +1 -1
- package/dest/test/upgrade_utils.js +3 -2
- package/dest/types.d.ts +57 -2
- package/dest/types.d.ts.map +1 -1
- package/dest/utils.d.ts +2 -2
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +10 -161
- package/dest/zkPassportVerifierAddress.d.ts +1 -1
- package/dest/zkPassportVerifierAddress.js +1 -1
- package/package.json +27 -13
- package/src/client.ts +1 -1
- package/src/config.ts +177 -65
- package/src/contracts/empire_base.ts +7 -6
- package/src/contracts/empire_slashing_proposer.ts +18 -8
- package/src/contracts/fee_asset_handler.ts +1 -1
- package/src/contracts/governance.ts +3 -3
- package/src/contracts/governance_proposer.ts +14 -9
- package/src/contracts/multicall.ts +12 -10
- package/src/contracts/rollup.ts +170 -171
- package/src/contracts/slasher_contract.ts +22 -0
- package/src/contracts/tally_slashing_proposer.ts +63 -12
- package/src/deploy_l1_contracts.ts +610 -337
- package/src/forwarder_proxy.ts +108 -0
- package/src/l1_artifacts.ts +14 -6
- package/src/l1_contract_addresses.ts +17 -26
- package/src/l1_reader.ts +17 -9
- package/src/l1_tx_utils/README.md +177 -0
- package/src/l1_tx_utils/config.ts +161 -0
- package/src/l1_tx_utils/constants.ts +18 -0
- package/src/l1_tx_utils/factory.ts +64 -0
- package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +119 -0
- package/src/l1_tx_utils/index-blobs.ts +2 -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 +738 -0
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +77 -0
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +557 -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 +16 -8
- package/src/test/chain_monitor.ts +118 -36
- package/src/test/delayed_tx_utils.ts +2 -2
- package/src/test/eth_cheat_codes.ts +149 -30
- package/src/test/rollup_cheat_codes.ts +94 -52
- package/src/test/start_anvil.ts +2 -0
- package/src/test/tx_delayer.ts +4 -2
- package/src/test/upgrade_utils.ts +3 -2
- package/src/types.ts +62 -0
- package/src/utils.ts +12 -184
- package/src/zkPassportVerifierAddress.ts +1 -1
- package/dest/index.d.ts +0 -18
- package/dest/index.d.ts.map +0 -1
- package/dest/index.js +0 -17
- 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/index.ts +0 -17
- package/src/l1_tx_utils.ts +0 -1105
- package/src/l1_tx_utils_with_blobs.ts +0 -144
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/constants';
|
|
2
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import { SecretValue, getActiveNetworkName } from '@aztec/foundation/config';
|
|
3
|
-
import { keccak256String } from '@aztec/foundation/crypto';
|
|
4
|
+
import { keccak256String } from '@aztec/foundation/crypto/keccak';
|
|
5
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
6
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
|
-
import type { Fr } from '@aztec/foundation/fields';
|
|
6
7
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
7
8
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
8
9
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
9
|
-
import
|
|
10
|
+
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
10
11
|
|
|
11
12
|
import type { Abi, Narrow } from 'abitype';
|
|
12
|
-
import
|
|
13
|
+
import fs from 'fs';
|
|
14
|
+
import chunk from 'lodash.chunk';
|
|
13
15
|
import {
|
|
14
16
|
type Chain,
|
|
15
17
|
type ContractConstructorArgs,
|
|
@@ -33,7 +35,6 @@ import { createExtendedL1Client } from './client.js';
|
|
|
33
35
|
import {
|
|
34
36
|
type L1ContractsConfig,
|
|
35
37
|
getEntryQueueConfig,
|
|
36
|
-
getGSEConfiguration,
|
|
37
38
|
getGovernanceConfiguration,
|
|
38
39
|
getRewardBoostConfig,
|
|
39
40
|
getRewardConfig,
|
|
@@ -45,6 +46,7 @@ import { RegistryContract } from './contracts/registry.js';
|
|
|
45
46
|
import { RollupContract, SlashingProposerType } from './contracts/rollup.js';
|
|
46
47
|
import {
|
|
47
48
|
CoinIssuerArtifact,
|
|
49
|
+
DateGatedRelayerArtifact,
|
|
48
50
|
FeeAssetArtifact,
|
|
49
51
|
FeeAssetHandlerArtifact,
|
|
50
52
|
GSEArtifact,
|
|
@@ -63,21 +65,19 @@ import {
|
|
|
63
65
|
import type { L1ContractAddresses } from './l1_contract_addresses.js';
|
|
64
66
|
import {
|
|
65
67
|
type GasPrice,
|
|
66
|
-
type
|
|
68
|
+
type L1TxConfig,
|
|
67
69
|
type L1TxRequest,
|
|
68
70
|
L1TxUtils,
|
|
69
71
|
type L1TxUtilsConfig,
|
|
70
72
|
createL1TxUtilsFromViemWallet,
|
|
71
73
|
getL1TxUtilsConfigEnvVars,
|
|
72
|
-
} from './l1_tx_utils.js';
|
|
74
|
+
} from './l1_tx_utils/index.js';
|
|
73
75
|
import type { ExtendedViemWalletClient } from './types.js';
|
|
74
76
|
import { formatViemError } from './utils.js';
|
|
75
77
|
import { ZK_PASSPORT_DOMAIN, ZK_PASSPORT_SCOPE, ZK_PASSPORT_VERIFIER_ADDRESS } from './zkPassportVerifierAddress.js';
|
|
76
78
|
|
|
77
79
|
export const DEPLOYER_ADDRESS: Hex = '0x4e59b44847b379578588920cA78FbF26c0B4956C';
|
|
78
80
|
|
|
79
|
-
const networkName = getActiveNetworkName();
|
|
80
|
-
|
|
81
81
|
export type Operator = {
|
|
82
82
|
attester: EthAddress;
|
|
83
83
|
withdrawer: EthAddress;
|
|
@@ -148,8 +148,8 @@ export type VerificationRecord = {
|
|
|
148
148
|
export interface DeployL1ContractsArgs extends Omit<L1ContractsConfig, keyof L1TxUtilsConfig> {
|
|
149
149
|
/** The vk tree root. */
|
|
150
150
|
vkTreeRoot: Fr;
|
|
151
|
-
/** The
|
|
152
|
-
|
|
151
|
+
/** The hash of the protocol contracts. */
|
|
152
|
+
protocolContractsHash: Fr;
|
|
153
153
|
/** The genesis root of the archive tree. */
|
|
154
154
|
genesisArchiveRoot: Fr;
|
|
155
155
|
/** The salt for CREATE2 deployment. */
|
|
@@ -166,6 +166,8 @@ export interface DeployL1ContractsArgs extends Omit<L1ContractsConfig, keyof L1T
|
|
|
166
166
|
realVerifier: boolean;
|
|
167
167
|
/** The zk passport args */
|
|
168
168
|
zkPassportArgs?: ZKPassportArgs;
|
|
169
|
+
/** If provided, use this token for BOTH fee and staking assets (skip deployments) */
|
|
170
|
+
existingTokenAddress?: EthAddress;
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
export interface ZKPassportArgs {
|
|
@@ -177,39 +179,147 @@ export interface ZKPassportArgs {
|
|
|
177
179
|
zkPassportScope?: string;
|
|
178
180
|
}
|
|
179
181
|
|
|
182
|
+
// Minimal ERC20 ABI for validation purposes. We only read view methods.
|
|
183
|
+
const ERC20_VALIDATION_ABI = [
|
|
184
|
+
{
|
|
185
|
+
type: 'function',
|
|
186
|
+
name: 'totalSupply',
|
|
187
|
+
stateMutability: 'view',
|
|
188
|
+
inputs: [],
|
|
189
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
type: 'function',
|
|
193
|
+
name: 'name',
|
|
194
|
+
stateMutability: 'view',
|
|
195
|
+
inputs: [],
|
|
196
|
+
outputs: [{ name: '', type: 'string' }],
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
type: 'function',
|
|
200
|
+
name: 'symbol',
|
|
201
|
+
stateMutability: 'view',
|
|
202
|
+
inputs: [],
|
|
203
|
+
outputs: [{ name: '', type: 'string' }],
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
type: 'function',
|
|
207
|
+
name: 'decimals',
|
|
208
|
+
stateMutability: 'view',
|
|
209
|
+
inputs: [],
|
|
210
|
+
outputs: [{ name: '', type: 'uint8' }],
|
|
211
|
+
},
|
|
212
|
+
] as const;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Validates that the provided address points to a contract that resembles an ERC20 token.
|
|
216
|
+
* Checks for contract code and attempts common ERC20 view calls.
|
|
217
|
+
* Throws an error if validation fails.
|
|
218
|
+
*/
|
|
219
|
+
export async function validateExistingErc20TokenAddress(
|
|
220
|
+
l1Client: ExtendedViemWalletClient,
|
|
221
|
+
tokenAddress: EthAddress,
|
|
222
|
+
logger: Logger,
|
|
223
|
+
): Promise<void> {
|
|
224
|
+
const addressString = tokenAddress.toString();
|
|
225
|
+
|
|
226
|
+
// Ensure there is contract code at the address
|
|
227
|
+
const code = await l1Client.getCode({ address: addressString });
|
|
228
|
+
if (!code || code === '0x') {
|
|
229
|
+
throw new Error(`No contract code found at provided token address ${addressString}`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const contract = getContract({
|
|
233
|
+
address: getAddress(addressString),
|
|
234
|
+
abi: ERC20_VALIDATION_ABI,
|
|
235
|
+
client: l1Client,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Validate all required ERC20 methods in parallel
|
|
239
|
+
const checks = [
|
|
240
|
+
contract.read.totalSupply().then(total => typeof total === 'bigint'),
|
|
241
|
+
contract.read.name().then(() => true),
|
|
242
|
+
contract.read.symbol().then(() => true),
|
|
243
|
+
contract.read.decimals().then(dec => typeof dec === 'number' || typeof dec === 'bigint'),
|
|
244
|
+
];
|
|
245
|
+
|
|
246
|
+
const results = await Promise.allSettled(checks);
|
|
247
|
+
const failedChecks = results.filter(result => result.status === 'rejected' || result.value !== true);
|
|
248
|
+
|
|
249
|
+
if (failedChecks.length > 0) {
|
|
250
|
+
throw new Error(`Address ${addressString} does not appear to implement ERC20 view methods`);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
logger.verbose(`Validated existing token at ${addressString} appears to be ERC20-compatible`);
|
|
254
|
+
}
|
|
255
|
+
|
|
180
256
|
export const deploySharedContracts = async (
|
|
181
257
|
l1Client: ExtendedViemWalletClient,
|
|
182
258
|
deployer: L1Deployer,
|
|
183
259
|
args: DeployL1ContractsArgs,
|
|
184
260
|
logger: Logger,
|
|
185
261
|
) => {
|
|
186
|
-
|
|
262
|
+
const networkName = getActiveNetworkName();
|
|
263
|
+
|
|
264
|
+
logger.info(`Deploying shared contracts for network configuration: ${networkName}`);
|
|
187
265
|
|
|
188
266
|
const txHashes: Hex[] = [];
|
|
189
267
|
|
|
190
|
-
|
|
191
|
-
|
|
268
|
+
let feeAssetAddress: EthAddress;
|
|
269
|
+
let stakingAssetAddress: EthAddress;
|
|
270
|
+
if (args.existingTokenAddress) {
|
|
271
|
+
await validateExistingErc20TokenAddress(l1Client, args.existingTokenAddress, logger);
|
|
272
|
+
feeAssetAddress = args.existingTokenAddress;
|
|
273
|
+
stakingAssetAddress = args.existingTokenAddress;
|
|
274
|
+
logger.verbose(`Using existing token for fee and staking assets at ${args.existingTokenAddress}`);
|
|
275
|
+
} else {
|
|
276
|
+
const deployedFee = await deployer.deploy(FeeAssetArtifact, ['FeeJuice', 'FEE', l1Client.account.address]);
|
|
277
|
+
feeAssetAddress = deployedFee.address;
|
|
278
|
+
logger.verbose(`Deployed Fee Asset at ${feeAssetAddress}`);
|
|
192
279
|
|
|
193
|
-
|
|
194
|
-
|
|
280
|
+
// Mint a tiny bit of tokens to satisfy coin-issuer constraints
|
|
281
|
+
const { txHash } = await deployer.sendTransaction(
|
|
282
|
+
{
|
|
283
|
+
to: feeAssetAddress.toString(),
|
|
284
|
+
data: encodeFunctionData({
|
|
285
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
286
|
+
functionName: 'mint',
|
|
287
|
+
args: [l1Client.account.address, 1n * 10n ** 18n],
|
|
288
|
+
}),
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
// contract may not have been deployed yet (CREATE2 returns address before mining),
|
|
292
|
+
// which causes gas estimation to fail. Hardcode to 100k which is plenty for ERC20 mint.
|
|
293
|
+
gasLimit: 100_000n,
|
|
294
|
+
},
|
|
295
|
+
);
|
|
296
|
+
await l1Client.waitForTransactionReceipt({ hash: txHash });
|
|
297
|
+
logger.verbose(`Minted tiny bit of tokens to satisfy coin-issuer constraints in ${txHash}`);
|
|
195
298
|
|
|
196
|
-
|
|
299
|
+
const deployedStaking = await deployer.deploy(StakingAssetArtifact, ['Staking', 'STK', l1Client.account.address]);
|
|
300
|
+
stakingAssetAddress = deployedStaking.address;
|
|
301
|
+
logger.verbose(`Deployed Staking Asset at ${stakingAssetAddress}`);
|
|
197
302
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
303
|
+
await deployer.waitForDeployments();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const gseAddress = (
|
|
307
|
+
await deployer.deploy(GSEArtifact, [
|
|
308
|
+
l1Client.account.address,
|
|
309
|
+
stakingAssetAddress.toString(),
|
|
310
|
+
args.activationThreshold,
|
|
311
|
+
args.ejectionThreshold,
|
|
312
|
+
])
|
|
313
|
+
).address;
|
|
204
314
|
logger.verbose(`Deployed GSE at ${gseAddress}`);
|
|
205
315
|
|
|
206
|
-
const registryAddress = await deployer.deploy(RegistryArtifact, [
|
|
316
|
+
const { address: registryAddress } = await deployer.deploy(RegistryArtifact, [
|
|
207
317
|
l1Client.account.address,
|
|
208
318
|
feeAssetAddress.toString(),
|
|
209
319
|
]);
|
|
210
320
|
logger.verbose(`Deployed Registry at ${registryAddress}`);
|
|
211
321
|
|
|
212
|
-
const governanceProposerAddress = await deployer.deploy(GovernanceProposerArtifact, [
|
|
322
|
+
const { address: governanceProposerAddress } = await deployer.deploy(GovernanceProposerArtifact, [
|
|
213
323
|
registryAddress.toString(),
|
|
214
324
|
gseAddress.toString(),
|
|
215
325
|
BigInt(args.governanceProposerQuorum ?? args.governanceProposerRoundSize / 2 + 1),
|
|
@@ -219,7 +329,7 @@ export const deploySharedContracts = async (
|
|
|
219
329
|
|
|
220
330
|
// @note @LHerskind the assets are expected to be the same at some point, but for better
|
|
221
331
|
// configurability they are different for now.
|
|
222
|
-
const governanceAddress = await deployer.deploy(GovernanceArtifact, [
|
|
332
|
+
const { address: governanceAddress } = await deployer.deploy(GovernanceArtifact, [
|
|
223
333
|
stakingAssetAddress.toString(),
|
|
224
334
|
governanceProposerAddress.toString(),
|
|
225
335
|
gseAddress.toString(),
|
|
@@ -261,11 +371,20 @@ export const deploySharedContracts = async (
|
|
|
261
371
|
txHashes.push(txHash);
|
|
262
372
|
}
|
|
263
373
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
374
|
+
logger.verbose(`Waiting for deployments to complete`);
|
|
375
|
+
await deployer.waitForDeployments();
|
|
376
|
+
|
|
377
|
+
const coinIssuerAddress = (
|
|
378
|
+
await deployer.deploy(
|
|
379
|
+
CoinIssuerArtifact,
|
|
380
|
+
[
|
|
381
|
+
feeAssetAddress.toString(),
|
|
382
|
+
2n * 10n ** 17n, // hard cap of 20% per year
|
|
383
|
+
l1Client.account.address,
|
|
384
|
+
],
|
|
385
|
+
{ gasLimit: 1_000_000n, noSimulation: true },
|
|
386
|
+
)
|
|
387
|
+
).address;
|
|
269
388
|
logger.verbose(`Deployed CoinIssuer at ${coinIssuerAddress}`);
|
|
270
389
|
|
|
271
390
|
logger.verbose(`Waiting for deployments to complete`);
|
|
@@ -277,21 +396,22 @@ export const deploySharedContracts = async (
|
|
|
277
396
|
let stakingAssetHandlerAddress: EthAddress | undefined = undefined;
|
|
278
397
|
let zkPassportVerifierAddress: EthAddress | undefined = undefined;
|
|
279
398
|
|
|
280
|
-
// Only if not on mainnet will we deploy the handlers
|
|
281
|
-
if (l1Client.chain.id !== 1) {
|
|
399
|
+
// Only if not on mainnet will we deploy the handlers, and only when we control the token
|
|
400
|
+
if (l1Client.chain.id !== 1 && !args.existingTokenAddress) {
|
|
282
401
|
/* -------------------------------------------------------------------------- */
|
|
283
402
|
/* CHEAT CODES START HERE */
|
|
284
403
|
/* -------------------------------------------------------------------------- */
|
|
285
404
|
|
|
286
|
-
|
|
405
|
+
const deployedFeeAssetHandler = await deployer.deploy(FeeAssetHandlerArtifact, [
|
|
287
406
|
l1Client.account.address,
|
|
288
407
|
feeAssetAddress.toString(),
|
|
289
408
|
BigInt(1000n * 10n ** 18n),
|
|
290
409
|
]);
|
|
410
|
+
feeAssetHandlerAddress = deployedFeeAssetHandler.address;
|
|
291
411
|
logger.verbose(`Deployed FeeAssetHandler at ${feeAssetHandlerAddress}`);
|
|
292
412
|
|
|
293
|
-
// Only
|
|
294
|
-
if (
|
|
413
|
+
// Only add as minter if this is a new deployment (not reusing existing handler from failed previous run)
|
|
414
|
+
if (!deployedFeeAssetHandler.existed) {
|
|
295
415
|
const { txHash } = await deployer.sendTransaction({
|
|
296
416
|
to: feeAssetAddress.toString(),
|
|
297
417
|
data: encodeFunctionData({
|
|
@@ -316,6 +436,7 @@ export const deploySharedContracts = async (
|
|
|
316
436
|
stakingAsset: stakingAssetAddress.toString(),
|
|
317
437
|
registry: registryAddress.toString(),
|
|
318
438
|
withdrawer: AMIN.toString(),
|
|
439
|
+
validatorsToFlush: 16n,
|
|
319
440
|
mintInterval: BigInt(60 * 60 * 24),
|
|
320
441
|
depositsPerMint: BigInt(10),
|
|
321
442
|
depositMerkleRoot: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
@@ -329,7 +450,8 @@ export const deploySharedContracts = async (
|
|
|
329
450
|
skipMerkleCheck: true, // skip merkle check - needed for testing without generating proofs
|
|
330
451
|
} as const;
|
|
331
452
|
|
|
332
|
-
stakingAssetHandlerAddress = await deployer.deploy(StakingAssetHandlerArtifact, [stakingAssetHandlerDeployArgs])
|
|
453
|
+
stakingAssetHandlerAddress = (await deployer.deploy(StakingAssetHandlerArtifact, [stakingAssetHandlerDeployArgs]))
|
|
454
|
+
.address;
|
|
333
455
|
logger.verbose(`Deployed StakingAssetHandler at ${stakingAssetHandlerAddress}`);
|
|
334
456
|
|
|
335
457
|
const { txHash: stakingMinterTxHash } = await deployer.sendTransaction({
|
|
@@ -365,19 +487,23 @@ export const deploySharedContracts = async (
|
|
|
365
487
|
|
|
366
488
|
const rewardDistributorAddress = await registry.getRewardDistributor();
|
|
367
489
|
|
|
368
|
-
|
|
490
|
+
if (!args.existingTokenAddress) {
|
|
491
|
+
const checkpointReward = getRewardConfig(networkName).checkpointReward;
|
|
369
492
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
493
|
+
const funding = checkpointReward * 200000n;
|
|
494
|
+
const { txHash: fundRewardDistributorTxHash } = await deployer.sendTransaction({
|
|
495
|
+
to: feeAssetAddress.toString(),
|
|
496
|
+
data: encodeFunctionData({
|
|
497
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
498
|
+
functionName: 'mint',
|
|
499
|
+
args: [rewardDistributorAddress.toString(), funding],
|
|
500
|
+
}),
|
|
501
|
+
});
|
|
379
502
|
|
|
380
|
-
|
|
503
|
+
logger.verbose(`Funded reward distributor with ${funding} fee asset in ${fundRewardDistributorTxHash}`);
|
|
504
|
+
} else {
|
|
505
|
+
logger.verbose(`Skipping reward distributor funding as existing token is provided`);
|
|
506
|
+
}
|
|
381
507
|
|
|
382
508
|
/* -------------------------------------------------------------------------- */
|
|
383
509
|
/* FUND REWARD DISTRIBUTOR STOP */
|
|
@@ -400,7 +526,7 @@ export const deploySharedContracts = async (
|
|
|
400
526
|
|
|
401
527
|
const getZkPassportVerifierAddress = async (deployer: L1Deployer, args: DeployL1ContractsArgs): Promise<EthAddress> => {
|
|
402
528
|
if (args.zkPassportArgs?.mockZkPassportVerifier) {
|
|
403
|
-
return await deployer.deploy(mockVerifiers.mockZkPassportVerifier);
|
|
529
|
+
return (await deployer.deploy(mockVerifiers.mockZkPassportVerifier)).address;
|
|
404
530
|
}
|
|
405
531
|
return ZK_PASSPORT_VERIFIER_ADDRESS;
|
|
406
532
|
};
|
|
@@ -416,6 +542,199 @@ const getZkPassportScopes = (args: DeployL1ContractsArgs): [string, string] => {
|
|
|
416
542
|
return [domain, scope];
|
|
417
543
|
};
|
|
418
544
|
|
|
545
|
+
/**
|
|
546
|
+
* Generates verification records for a deployed rollup and its associated contracts (Inbox, Outbox, Slasher, etc).
|
|
547
|
+
* @param rollup - The deployed rollup contract.
|
|
548
|
+
* @param deployer - The L1 deployer instance.
|
|
549
|
+
* @param args - The deployment arguments used for the rollup.
|
|
550
|
+
* @param addresses - The L1 contract addresses.
|
|
551
|
+
* @param extendedClient - The extended viem wallet client.
|
|
552
|
+
* @param logger - The logger.
|
|
553
|
+
*/
|
|
554
|
+
async function generateRollupVerificationRecords(
|
|
555
|
+
rollup: RollupContract,
|
|
556
|
+
deployer: L1Deployer,
|
|
557
|
+
args: {
|
|
558
|
+
slashingVetoer: EthAddress;
|
|
559
|
+
slashingRoundSizeInEpochs: number;
|
|
560
|
+
aztecEpochDuration: number;
|
|
561
|
+
slashingQuorum?: number;
|
|
562
|
+
slashingLifetimeInRounds: number;
|
|
563
|
+
slashingExecutionDelayInRounds: number;
|
|
564
|
+
slasherFlavor: 'none' | 'tally' | 'empire';
|
|
565
|
+
slashAmountSmall: bigint;
|
|
566
|
+
slashAmountMedium: bigint;
|
|
567
|
+
slashAmountLarge: bigint;
|
|
568
|
+
aztecTargetCommitteeSize: number;
|
|
569
|
+
slashingOffsetInRounds: number;
|
|
570
|
+
},
|
|
571
|
+
addresses: Pick<L1ContractAddresses, 'feeJuiceAddress'>,
|
|
572
|
+
extendedClient: ExtendedViemWalletClient,
|
|
573
|
+
logger: Logger,
|
|
574
|
+
): Promise<void> {
|
|
575
|
+
try {
|
|
576
|
+
// Add Inbox / Outbox verification records (constructor args are created inside RollupCore)
|
|
577
|
+
const rollupAddr = rollup.address;
|
|
578
|
+
const rollupAddresses = await rollup.getRollupAddresses();
|
|
579
|
+
const inboxAddr = rollupAddresses.inboxAddress.toString();
|
|
580
|
+
const outboxAddr = rollupAddresses.outboxAddress.toString();
|
|
581
|
+
const feeAsset = rollupAddresses.feeJuiceAddress.toString();
|
|
582
|
+
const version = await rollup.getVersion();
|
|
583
|
+
|
|
584
|
+
const inboxCtor = encodeAbiParameters(
|
|
585
|
+
[{ type: 'address' }, { type: 'address' }, { type: 'uint256' }, { type: 'uint256' }],
|
|
586
|
+
[rollupAddr, feeAsset, version, BigInt(L1_TO_L2_MSG_SUBTREE_HEIGHT)],
|
|
587
|
+
);
|
|
588
|
+
|
|
589
|
+
const outboxCtor = encodeAbiParameters([{ type: 'address' }, { type: 'uint256' }], [rollupAddr, version]);
|
|
590
|
+
|
|
591
|
+
deployer.verificationRecords.push(
|
|
592
|
+
{ name: 'Inbox', address: inboxAddr, constructorArgsHex: inboxCtor, libraries: [] },
|
|
593
|
+
{ name: 'Outbox', address: outboxAddr, constructorArgsHex: outboxCtor, libraries: [] },
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
// Include Slasher and SlashingProposer (if deployed) in verification data
|
|
597
|
+
try {
|
|
598
|
+
const slasherAddrHex = await rollup.getSlasherAddress();
|
|
599
|
+
const slasherAddr = EthAddress.fromString(slasherAddrHex);
|
|
600
|
+
if (!slasherAddr.isZero()) {
|
|
601
|
+
// Slasher constructor: (address _vetoer, address _governance)
|
|
602
|
+
const slasherCtor = encodeAbiParameters(
|
|
603
|
+
[{ type: 'address' }, { type: 'address' }],
|
|
604
|
+
[args.slashingVetoer.toString(), extendedClient.account.address],
|
|
605
|
+
);
|
|
606
|
+
deployer.verificationRecords.push({
|
|
607
|
+
name: 'Slasher',
|
|
608
|
+
address: slasherAddr.toString(),
|
|
609
|
+
constructorArgsHex: slasherCtor,
|
|
610
|
+
libraries: [],
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
// Proposer address is stored in Slasher.PROPOSER()
|
|
614
|
+
const proposerAddr = (await rollup.getSlashingProposerAddress()).toString();
|
|
615
|
+
|
|
616
|
+
// Compute constructor args matching deployment path in RollupCore
|
|
617
|
+
const computedRoundSize = BigInt(args.slashingRoundSizeInEpochs * args.aztecEpochDuration);
|
|
618
|
+
const computedQuorum = BigInt(
|
|
619
|
+
args.slashingQuorum ?? (args.slashingRoundSizeInEpochs * args.aztecEpochDuration) / 2 + 1,
|
|
620
|
+
);
|
|
621
|
+
const lifetimeInRounds = BigInt(args.slashingLifetimeInRounds);
|
|
622
|
+
const executionDelayInRounds = BigInt(args.slashingExecutionDelayInRounds);
|
|
623
|
+
|
|
624
|
+
if (args.slasherFlavor === 'tally') {
|
|
625
|
+
const slashAmounts: readonly [bigint, bigint, bigint] = [
|
|
626
|
+
args.slashAmountSmall,
|
|
627
|
+
args.slashAmountMedium,
|
|
628
|
+
args.slashAmountLarge,
|
|
629
|
+
];
|
|
630
|
+
const committeeSize = BigInt(args.aztecTargetCommitteeSize);
|
|
631
|
+
const epochDuration = BigInt(args.aztecEpochDuration);
|
|
632
|
+
const slashOffsetInRounds = BigInt(args.slashingOffsetInRounds);
|
|
633
|
+
|
|
634
|
+
const proposerCtor = encodeAbiParameters(
|
|
635
|
+
[
|
|
636
|
+
{ type: 'address' },
|
|
637
|
+
{ type: 'address' },
|
|
638
|
+
{ type: 'uint256' },
|
|
639
|
+
{ type: 'uint256' },
|
|
640
|
+
{ type: 'uint256' },
|
|
641
|
+
{ type: 'uint256' },
|
|
642
|
+
{ type: 'uint256[3]' },
|
|
643
|
+
{ type: 'uint256' },
|
|
644
|
+
{ type: 'uint256' },
|
|
645
|
+
{ type: 'uint256' },
|
|
646
|
+
],
|
|
647
|
+
[
|
|
648
|
+
rollup.address,
|
|
649
|
+
slasherAddr.toString(),
|
|
650
|
+
computedQuorum,
|
|
651
|
+
computedRoundSize,
|
|
652
|
+
lifetimeInRounds,
|
|
653
|
+
executionDelayInRounds,
|
|
654
|
+
slashAmounts,
|
|
655
|
+
committeeSize,
|
|
656
|
+
epochDuration,
|
|
657
|
+
slashOffsetInRounds,
|
|
658
|
+
],
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
deployer.verificationRecords.push({
|
|
662
|
+
name: 'TallySlashingProposer',
|
|
663
|
+
address: proposerAddr,
|
|
664
|
+
constructorArgsHex: proposerCtor,
|
|
665
|
+
libraries: [],
|
|
666
|
+
});
|
|
667
|
+
} else if (args.slasherFlavor === 'empire') {
|
|
668
|
+
const proposerCtor = encodeAbiParameters(
|
|
669
|
+
[
|
|
670
|
+
{ type: 'address' },
|
|
671
|
+
{ type: 'address' },
|
|
672
|
+
{ type: 'uint256' },
|
|
673
|
+
{ type: 'uint256' },
|
|
674
|
+
{ type: 'uint256' },
|
|
675
|
+
{ type: 'uint256' },
|
|
676
|
+
],
|
|
677
|
+
[
|
|
678
|
+
rollup.address,
|
|
679
|
+
slasherAddr.toString(),
|
|
680
|
+
computedQuorum,
|
|
681
|
+
computedRoundSize,
|
|
682
|
+
lifetimeInRounds,
|
|
683
|
+
executionDelayInRounds,
|
|
684
|
+
],
|
|
685
|
+
);
|
|
686
|
+
|
|
687
|
+
deployer.verificationRecords.push({
|
|
688
|
+
name: 'EmpireSlashingProposer',
|
|
689
|
+
address: proposerAddr,
|
|
690
|
+
constructorArgsHex: proposerCtor,
|
|
691
|
+
libraries: [],
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
} catch (e) {
|
|
696
|
+
logger.warn(`Failed to add Slasher/Proposer verification records: ${String(e)}`);
|
|
697
|
+
}
|
|
698
|
+
} catch (e) {
|
|
699
|
+
throw new Error(`Failed to generate rollup verification records: ${String(e)}`);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Writes verification records to a JSON file for later forge verify.
|
|
705
|
+
* @param deployer - The L1 deployer containing verification records.
|
|
706
|
+
* @param outputDirectory - The directory to write the verification file to.
|
|
707
|
+
* @param chainId - The chain ID.
|
|
708
|
+
* @param filenameSuffix - Optional suffix for the filename (e.g., 'upgrade').
|
|
709
|
+
* @param logger - The logger.
|
|
710
|
+
*/
|
|
711
|
+
async function writeVerificationJson(
|
|
712
|
+
deployer: L1Deployer,
|
|
713
|
+
outputDirectory: string,
|
|
714
|
+
chainId: number,
|
|
715
|
+
filenameSuffix: string = '',
|
|
716
|
+
logger: Logger,
|
|
717
|
+
): Promise<void> {
|
|
718
|
+
try {
|
|
719
|
+
const date = new Date();
|
|
720
|
+
const formattedDate = date.toISOString().slice(2, 19).replace(/[-T:]/g, '');
|
|
721
|
+
// Ensure the verification output directory exists
|
|
722
|
+
await fs.promises.mkdir(outputDirectory, { recursive: true });
|
|
723
|
+
const suffix = filenameSuffix ? `-${filenameSuffix}` : '';
|
|
724
|
+
const verificationOutputPath = `${outputDirectory}/l1-verify${suffix}-${chainId}-${formattedDate.slice(0, 6)}-${formattedDate.slice(6)}.json`;
|
|
725
|
+
const networkName = getActiveNetworkName();
|
|
726
|
+
const verificationData = {
|
|
727
|
+
chainId: chainId,
|
|
728
|
+
network: networkName,
|
|
729
|
+
records: deployer.verificationRecords,
|
|
730
|
+
};
|
|
731
|
+
await fs.promises.writeFile(verificationOutputPath, JSON.stringify(verificationData, null, 2));
|
|
732
|
+
logger.info(`Wrote L1 verification data to ${verificationOutputPath}`);
|
|
733
|
+
} catch (e) {
|
|
734
|
+
logger.warn(`Failed to write L1 verification data file: ${String(e)}`);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
419
738
|
/**
|
|
420
739
|
* Deploys a new rollup, using the existing canonical version to derive certain values (addresses of assets etc).
|
|
421
740
|
* @param clients - The L1 clients.
|
|
@@ -423,6 +742,7 @@ const getZkPassportScopes = (args: DeployL1ContractsArgs): [string, string] => {
|
|
|
423
742
|
* @param registryAddress - The address of the registry.
|
|
424
743
|
* @param logger - The logger.
|
|
425
744
|
* @param txUtilsConfig - The L1 tx utils config.
|
|
745
|
+
* @param createVerificationJson - Optional path to write verification data for forge verify.
|
|
426
746
|
*/
|
|
427
747
|
export const deployRollupForUpgrade = async (
|
|
428
748
|
extendedClient: ExtendedViemWalletClient,
|
|
@@ -433,6 +753,7 @@ export const deployRollupForUpgrade = async (
|
|
|
433
753
|
registryAddress: EthAddress,
|
|
434
754
|
logger: Logger,
|
|
435
755
|
txUtilsConfig: L1TxUtilsConfig,
|
|
756
|
+
createVerificationJson: string | false = false,
|
|
436
757
|
) => {
|
|
437
758
|
const deployer = new L1Deployer(
|
|
438
759
|
extendedClient,
|
|
@@ -441,6 +762,7 @@ export const deployRollupForUpgrade = async (
|
|
|
441
762
|
args.acceleratedTestDeployments,
|
|
442
763
|
logger,
|
|
443
764
|
txUtilsConfig,
|
|
765
|
+
!!createVerificationJson,
|
|
444
766
|
);
|
|
445
767
|
|
|
446
768
|
const addresses = await RegistryContract.collectAddresses(extendedClient, registryAddress, 'canonical');
|
|
@@ -449,11 +771,17 @@ export const deployRollupForUpgrade = async (
|
|
|
449
771
|
|
|
450
772
|
await deployer.waitForDeployments();
|
|
451
773
|
|
|
774
|
+
// Write verification data (constructor args + linked libraries) to file for later forge verify
|
|
775
|
+
if (createVerificationJson) {
|
|
776
|
+
await generateRollupVerificationRecords(rollup, deployer, args, addresses, extendedClient, logger);
|
|
777
|
+
await writeVerificationJson(deployer, createVerificationJson, extendedClient.chain.id, 'upgrade', logger);
|
|
778
|
+
}
|
|
779
|
+
|
|
452
780
|
return { rollup, slashFactoryAddress };
|
|
453
781
|
};
|
|
454
782
|
|
|
455
783
|
export const deploySlashFactory = async (deployer: L1Deployer, rollupAddress: Hex, logger: Logger) => {
|
|
456
|
-
const slashFactoryAddress = await deployer.deploy(SlashFactoryArtifact, [rollupAddress]);
|
|
784
|
+
const slashFactoryAddress = (await deployer.deploy(SlashFactoryArtifact, [rollupAddress])).address;
|
|
457
785
|
logger.verbose(`Deployed SlashFactory at ${slashFactoryAddress}`);
|
|
458
786
|
return slashFactoryAddress;
|
|
459
787
|
};
|
|
@@ -462,10 +790,12 @@ export const deployUpgradePayload = async (
|
|
|
462
790
|
deployer: L1Deployer,
|
|
463
791
|
addresses: Pick<L1ContractAddresses, 'registryAddress' | 'rollupAddress'>,
|
|
464
792
|
) => {
|
|
465
|
-
const payloadAddress =
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
793
|
+
const payloadAddress = (
|
|
794
|
+
await deployer.deploy(RegisterNewRollupVersionPayloadArtifact, [
|
|
795
|
+
addresses.registryAddress.toString(),
|
|
796
|
+
addresses.rollupAddress.toString(),
|
|
797
|
+
])
|
|
798
|
+
).address;
|
|
469
799
|
|
|
470
800
|
return payloadAddress;
|
|
471
801
|
};
|
|
@@ -509,6 +839,7 @@ export const deployRollup = async (
|
|
|
509
839
|
if (!addresses.gseAddress) {
|
|
510
840
|
throw new Error('GSE address is required when deploying');
|
|
511
841
|
}
|
|
842
|
+
const networkName = getActiveNetworkName();
|
|
512
843
|
|
|
513
844
|
logger.info(`Deploying rollup using network configuration: ${networkName}`);
|
|
514
845
|
|
|
@@ -517,10 +848,10 @@ export const deployRollup = async (
|
|
|
517
848
|
let epochProofVerifier = EthAddress.ZERO;
|
|
518
849
|
|
|
519
850
|
if (args.realVerifier) {
|
|
520
|
-
epochProofVerifier = await deployer.deploy(l1ArtifactsVerifiers.honkVerifier);
|
|
851
|
+
epochProofVerifier = (await deployer.deploy(l1ArtifactsVerifiers.honkVerifier)).address;
|
|
521
852
|
logger.verbose(`Rollup will use the real verifier at ${epochProofVerifier}`);
|
|
522
853
|
} else {
|
|
523
|
-
epochProofVerifier = await deployer.deploy(mockVerifiers.mockVerifier);
|
|
854
|
+
epochProofVerifier = (await deployer.deploy(mockVerifiers.mockVerifier)).address;
|
|
524
855
|
logger.verbose(`Rollup will use the mock verifier at ${epochProofVerifier}`);
|
|
525
856
|
}
|
|
526
857
|
|
|
@@ -533,6 +864,8 @@ export const deployRollup = async (
|
|
|
533
864
|
aztecSlotDuration: BigInt(args.aztecSlotDuration),
|
|
534
865
|
aztecEpochDuration: BigInt(args.aztecEpochDuration),
|
|
535
866
|
targetCommitteeSize: BigInt(args.aztecTargetCommitteeSize),
|
|
867
|
+
lagInEpochsForValidatorSet: BigInt(args.lagInEpochsForValidatorSet),
|
|
868
|
+
lagInEpochsForRandao: BigInt(args.lagInEpochsForRandao),
|
|
536
869
|
aztecProofSubmissionEpochs: BigInt(args.aztecProofSubmissionEpochs),
|
|
537
870
|
slashingQuorum: BigInt(args.slashingQuorum ?? (args.slashingRoundSizeInEpochs * args.aztecEpochDuration) / 2 + 1),
|
|
538
871
|
slashingRoundSize: BigInt(args.slashingRoundSizeInEpochs * args.aztecEpochDuration),
|
|
@@ -543,17 +876,20 @@ export const deployRollup = async (
|
|
|
543
876
|
provingCostPerMana: args.provingCostPerMana,
|
|
544
877
|
rewardConfig: rewardConfig,
|
|
545
878
|
version: 0,
|
|
546
|
-
rewardBoostConfig: getRewardBoostConfig(
|
|
879
|
+
rewardBoostConfig: getRewardBoostConfig(),
|
|
547
880
|
stakingQueueConfig: getEntryQueueConfig(networkName),
|
|
548
881
|
exitDelaySeconds: BigInt(args.exitDelaySeconds),
|
|
549
882
|
slasherFlavor: slasherFlavorToSolidityEnum(args.slasherFlavor),
|
|
550
883
|
slashingOffsetInRounds: BigInt(args.slashingOffsetInRounds),
|
|
551
884
|
slashAmounts: [args.slashAmountSmall, args.slashAmountMedium, args.slashAmountLarge],
|
|
885
|
+
localEjectionThreshold: args.localEjectionThreshold,
|
|
886
|
+
slashingDisableDuration: BigInt(args.slashingDisableDuration ?? 0n),
|
|
887
|
+
earliestRewardsClaimableTimestamp: 0n,
|
|
552
888
|
};
|
|
553
889
|
|
|
554
890
|
const genesisStateArgs = {
|
|
555
891
|
vkTreeRoot: args.vkTreeRoot.toString(),
|
|
556
|
-
|
|
892
|
+
protocolContractsHash: args.protocolContractsHash.toString(),
|
|
557
893
|
genesisArchiveRoot: args.genesisArchiveRoot.toString(),
|
|
558
894
|
};
|
|
559
895
|
|
|
@@ -579,8 +915,10 @@ export const deployRollup = async (
|
|
|
579
915
|
rollupConfigArgs,
|
|
580
916
|
] as const;
|
|
581
917
|
|
|
582
|
-
const rollupAddress = await deployer.deploy(RollupArtifact, rollupArgs, {
|
|
583
|
-
|
|
918
|
+
const { address: rollupAddress, existed: rollupExisted } = await deployer.deploy(RollupArtifact, rollupArgs, {
|
|
919
|
+
gasLimit: 15_000_000n,
|
|
920
|
+
});
|
|
921
|
+
logger.verbose(`Deployed Rollup at ${rollupAddress}, already existed: ${rollupExisted}`, rollupConfigArgs);
|
|
584
922
|
|
|
585
923
|
const rollupContract = new RollupContract(extendedClient, rollupAddress);
|
|
586
924
|
|
|
@@ -588,24 +926,29 @@ export const deployRollup = async (
|
|
|
588
926
|
logger.verbose(`All core contracts have been deployed`);
|
|
589
927
|
|
|
590
928
|
if (args.feeJuicePortalInitialBalance && args.feeJuicePortalInitialBalance > 0n) {
|
|
591
|
-
|
|
929
|
+
// Skip funding when using an external token, as we likely don't have mint permissions
|
|
930
|
+
if (!('existingTokenAddress' in args) || !args.existingTokenAddress) {
|
|
931
|
+
const feeJuicePortalAddress = await rollupContract.getFeeJuicePortal();
|
|
592
932
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
933
|
+
// In fast mode, use the L1TxUtils to send transactions with nonce management
|
|
934
|
+
const { txHash: mintTxHash } = await deployer.sendTransaction({
|
|
935
|
+
to: addresses.feeJuiceAddress.toString(),
|
|
936
|
+
data: encodeFunctionData({
|
|
937
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
938
|
+
functionName: 'mint',
|
|
939
|
+
args: [feeJuicePortalAddress.toString(), args.feeJuicePortalInitialBalance],
|
|
940
|
+
}),
|
|
941
|
+
});
|
|
942
|
+
logger.verbose(
|
|
943
|
+
`Funding fee juice portal with ${args.feeJuicePortalInitialBalance} fee juice in ${mintTxHash} (accelerated test deployments)`,
|
|
944
|
+
);
|
|
945
|
+
txHashes.push(mintTxHash);
|
|
946
|
+
} else {
|
|
947
|
+
logger.verbose('Skipping fee juice portal funding due to external token usage');
|
|
948
|
+
}
|
|
606
949
|
}
|
|
607
950
|
|
|
608
|
-
const slashFactoryAddress = await deployer.deploy(SlashFactoryArtifact, [rollupAddress.toString()]);
|
|
951
|
+
const slashFactoryAddress = (await deployer.deploy(SlashFactoryArtifact, [rollupAddress.toString()])).address;
|
|
609
952
|
logger.verbose(`Deployed SlashFactory at ${slashFactoryAddress}`);
|
|
610
953
|
|
|
611
954
|
// We need to call a function on the registry to set the various contract addresses.
|
|
@@ -667,7 +1010,17 @@ export const deployRollup = async (
|
|
|
667
1010
|
logger.verbose(`Not the owner of the gse, skipping rollup addition`);
|
|
668
1011
|
}
|
|
669
1012
|
|
|
670
|
-
|
|
1013
|
+
const activeAttestorCount = await rollupContract.getActiveAttesterCount();
|
|
1014
|
+
const queuedAttestorCount = await rollupContract.getEntryQueueLength();
|
|
1015
|
+
logger.info(`Rollup has ${activeAttestorCount} active attestors and ${queuedAttestorCount} queued attestors`);
|
|
1016
|
+
|
|
1017
|
+
const shouldAddValidators = activeAttestorCount === 0n && queuedAttestorCount === 0n;
|
|
1018
|
+
|
|
1019
|
+
if (
|
|
1020
|
+
args.initialValidators &&
|
|
1021
|
+
shouldAddValidators &&
|
|
1022
|
+
(await gseContract.read.isRollupRegistered([rollupContract.address]))
|
|
1023
|
+
) {
|
|
671
1024
|
await addMultipleValidators(
|
|
672
1025
|
extendedClient,
|
|
673
1026
|
deployer,
|
|
@@ -715,6 +1068,7 @@ export const handoverToGovernance = async (
|
|
|
715
1068
|
governanceAddress: EthAddress,
|
|
716
1069
|
logger: Logger,
|
|
717
1070
|
acceleratedTestDeployments: boolean | undefined,
|
|
1071
|
+
useExternalToken: boolean = false,
|
|
718
1072
|
) => {
|
|
719
1073
|
// We need to call a function on the registry to set the various contract addresses.
|
|
720
1074
|
const registryContract = getContract({
|
|
@@ -780,7 +1134,10 @@ export const handoverToGovernance = async (
|
|
|
780
1134
|
txHashes.push(transferOwnershipTxHash);
|
|
781
1135
|
}
|
|
782
1136
|
|
|
783
|
-
if (
|
|
1137
|
+
if (
|
|
1138
|
+
!useExternalToken &&
|
|
1139
|
+
(acceleratedTestDeployments || (await feeAsset.read.owner()) !== coinIssuerAddress.toString())
|
|
1140
|
+
) {
|
|
784
1141
|
const { txHash } = await deployer.sendTransaction(
|
|
785
1142
|
{
|
|
786
1143
|
to: feeAssetAddress.toString(),
|
|
@@ -807,23 +1164,28 @@ export const handoverToGovernance = async (
|
|
|
807
1164
|
);
|
|
808
1165
|
logger.verbose(`Accept ownership of fee asset in ${acceptTokenOwnershipTxHash}`);
|
|
809
1166
|
txHashes.push(acceptTokenOwnershipTxHash);
|
|
1167
|
+
} else if (useExternalToken) {
|
|
1168
|
+
logger.verbose('Skipping fee asset ownership transfer due to external token usage');
|
|
810
1169
|
}
|
|
811
1170
|
|
|
1171
|
+
// Either deploy or at least predict the address of the date gated relayer
|
|
1172
|
+
const dateGatedRelayer = await deployer.deploy(DateGatedRelayerArtifact, [
|
|
1173
|
+
governanceAddress.toString(),
|
|
1174
|
+
1798761600n, // 2027-01-01 00:00:00 UTC
|
|
1175
|
+
]);
|
|
1176
|
+
|
|
812
1177
|
// 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
|
-
) {
|
|
1178
|
+
if (acceleratedTestDeployments || (await coinIssuerContract.read.owner()) === deployer.client.account.address) {
|
|
817
1179
|
const { txHash: transferOwnershipTxHash } = await deployer.sendTransaction({
|
|
818
1180
|
to: coinIssuerContract.address,
|
|
819
1181
|
data: encodeFunctionData({
|
|
820
1182
|
abi: CoinIssuerArtifact.contractAbi,
|
|
821
1183
|
functionName: 'transferOwnership',
|
|
822
|
-
args: [getAddress(
|
|
1184
|
+
args: [getAddress(dateGatedRelayer.address.toString())],
|
|
823
1185
|
}),
|
|
824
1186
|
});
|
|
825
1187
|
logger.verbose(
|
|
826
|
-
`Transferring the ownership of the coin issuer contract at ${coinIssuerAddress} to the
|
|
1188
|
+
`Transferring the ownership of the coin issuer contract at ${coinIssuerAddress} to the DateGatedRelayer ${dateGatedRelayer.address} in tx ${transferOwnershipTxHash}`,
|
|
827
1189
|
);
|
|
828
1190
|
txHashes.push(transferOwnershipTxHash);
|
|
829
1191
|
}
|
|
@@ -831,6 +1193,8 @@ export const handoverToGovernance = async (
|
|
|
831
1193
|
// Wait for all actions to be mined
|
|
832
1194
|
await deployer.waitForDeployments();
|
|
833
1195
|
await Promise.all(txHashes.map(txHash => extendedClient.waitForTransactionReceipt({ hash: txHash })));
|
|
1196
|
+
|
|
1197
|
+
return { dateGatedRelayerAddress: dateGatedRelayer.address };
|
|
834
1198
|
};
|
|
835
1199
|
|
|
836
1200
|
/*
|
|
@@ -877,100 +1241,112 @@ export const addMultipleValidators = async (
|
|
|
877
1241
|
validators = enrichedValidators.filter(v => v.status === 0).map(v => v.operator);
|
|
878
1242
|
}
|
|
879
1243
|
|
|
880
|
-
if (validators.length
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1244
|
+
if (validators.length === 0) {
|
|
1245
|
+
logger.warn('No validators to add. Skipping.');
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
const gseContract = new GSEContract(extendedClient, gseAddress);
|
|
1250
|
+
const multiAdder = (await deployer.deploy(MultiAdderArtifact, [rollupAddress, deployer.client.account.address]))
|
|
1251
|
+
.address;
|
|
1252
|
+
|
|
1253
|
+
const makeValidatorTuples = async (validator: Operator) => {
|
|
1254
|
+
const registrationTuple = await gseContract.makeRegistrationTuple(validator.bn254SecretKey.getValue());
|
|
1255
|
+
return {
|
|
1256
|
+
attester: getAddress(validator.attester.toString()),
|
|
1257
|
+
withdrawer: getAddress(validator.withdrawer.toString()),
|
|
1258
|
+
...registrationTuple,
|
|
891
1259
|
};
|
|
1260
|
+
};
|
|
892
1261
|
|
|
893
|
-
|
|
1262
|
+
const validatorsTuples = await Promise.all(validators.map(makeValidatorTuples));
|
|
894
1263
|
|
|
895
|
-
|
|
896
|
-
|
|
1264
|
+
// Mint tokens, approve them, use cheat code to initialize validator set without setting up the epoch.
|
|
1265
|
+
const stakeNeeded = activationThreshold * BigInt(validators.length);
|
|
897
1266
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1267
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction({
|
|
1268
|
+
to: stakingAssetAddress,
|
|
1269
|
+
data: encodeFunctionData({
|
|
1270
|
+
abi: StakingAssetArtifact.contractAbi,
|
|
1271
|
+
functionName: 'mint',
|
|
1272
|
+
args: [multiAdder.toString(), stakeNeeded],
|
|
1273
|
+
}),
|
|
1274
|
+
});
|
|
906
1275
|
|
|
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
|
-
);
|
|
1276
|
+
const entryQueueLengthBefore = await rollup.getEntryQueueLength();
|
|
1277
|
+
const validatorCountBefore = await rollup.getActiveAttesterCount();
|
|
928
1278
|
|
|
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
|
-
}
|
|
1279
|
+
logger.info(`Adding ${validators.length} validators to the rollup`);
|
|
957
1280
|
|
|
958
|
-
|
|
959
|
-
const validatorCountAfter = await rollup.getActiveAttesterCount();
|
|
1281
|
+
const chunkSize = 16;
|
|
960
1282
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1283
|
+
// We will add `chunkSize` validators to the queue until we have covered all of our validators.
|
|
1284
|
+
// The `chunkSize` needs to be small enough to fit inside a single tx, therefore 16.
|
|
1285
|
+
for (const c of chunk(validatorsTuples, chunkSize)) {
|
|
1286
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
1287
|
+
{
|
|
1288
|
+
to: multiAdder.toString(),
|
|
1289
|
+
data: encodeFunctionData({
|
|
1290
|
+
abi: MultiAdderArtifact.contractAbi,
|
|
1291
|
+
functionName: 'addValidators',
|
|
1292
|
+
args: [c, BigInt(0)],
|
|
1293
|
+
}),
|
|
1294
|
+
},
|
|
1295
|
+
{
|
|
1296
|
+
gasLimit: 16_000_000n,
|
|
1297
|
+
},
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
// After adding to the queue, we will now try to flush from it.
|
|
1302
|
+
// We are explicitly doing this as a second step instead of as part of adding to benefit
|
|
1303
|
+
// from the accounting used to speed the process up.
|
|
1304
|
+
// As the queue computes the amount of possible flushes in an epoch when told to flush,
|
|
1305
|
+
// waiting until we have added all we want allows us to benefit in the case were we added
|
|
1306
|
+
// enough to pass the bootstrap set size without needing to wait another epoch.
|
|
1307
|
+
// This is useful when we are testing as it speeds up the tests slightly.
|
|
1308
|
+
while (true) {
|
|
1309
|
+
// If the queue is empty, we can break
|
|
1310
|
+
if ((await rollup.getEntryQueueLength()) == 0n) {
|
|
1311
|
+
break;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// If there are no available validator flushes, no need to even try
|
|
1315
|
+
if ((await rollup.getAvailableValidatorFlushes()) == 0n) {
|
|
1316
|
+
break;
|
|
968
1317
|
}
|
|
969
1318
|
|
|
970
|
-
|
|
971
|
-
|
|
1319
|
+
// Note that we are flushing at most `chunkSize` at each call
|
|
1320
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
1321
|
+
{
|
|
1322
|
+
to: rollup.address,
|
|
1323
|
+
data: encodeFunctionData({
|
|
1324
|
+
abi: RollupArtifact.contractAbi,
|
|
1325
|
+
functionName: 'flushEntryQueue',
|
|
1326
|
+
args: [BigInt(chunkSize)],
|
|
1327
|
+
}),
|
|
1328
|
+
},
|
|
1329
|
+
{
|
|
1330
|
+
gasLimit: 16_000_000n,
|
|
1331
|
+
},
|
|
972
1332
|
);
|
|
973
1333
|
}
|
|
1334
|
+
|
|
1335
|
+
const entryQueueLengthAfter = await rollup.getEntryQueueLength();
|
|
1336
|
+
const validatorCountAfter = await rollup.getActiveAttesterCount();
|
|
1337
|
+
|
|
1338
|
+
if (
|
|
1339
|
+
entryQueueLengthAfter + validatorCountAfter <
|
|
1340
|
+
entryQueueLengthBefore + validatorCountBefore + BigInt(validators.length)
|
|
1341
|
+
) {
|
|
1342
|
+
throw new Error(
|
|
1343
|
+
`Failed to add ${validators.length} validators. Active validators: ${validatorCountBefore} -> ${validatorCountAfter}. Queue: ${entryQueueLengthBefore} -> ${entryQueueLengthAfter}. A likely issue is the bootstrap size.`,
|
|
1344
|
+
);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
logger.info(
|
|
1348
|
+
`Added ${validators.length} validators. Active validators: ${validatorCountBefore} -> ${validatorCountAfter}. Queue: ${entryQueueLengthBefore} -> ${entryQueueLengthAfter}`,
|
|
1349
|
+
);
|
|
974
1350
|
}
|
|
975
1351
|
};
|
|
976
1352
|
|
|
@@ -993,11 +1369,13 @@ export const cheat_initializeFeeAssetHandler = async (
|
|
|
993
1369
|
feeAssetHandlerAddress: EthAddress;
|
|
994
1370
|
txHash: Hex;
|
|
995
1371
|
}> => {
|
|
996
|
-
const feeAssetHandlerAddress =
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1372
|
+
const feeAssetHandlerAddress = (
|
|
1373
|
+
await deployer.deploy(FeeAssetHandlerArtifact, [
|
|
1374
|
+
extendedClient.account.address,
|
|
1375
|
+
feeAssetAddress.toString(),
|
|
1376
|
+
BigInt(1e18),
|
|
1377
|
+
])
|
|
1378
|
+
).address;
|
|
1001
1379
|
logger.verbose(`Deployed FeeAssetHandler at ${feeAssetHandlerAddress}`);
|
|
1002
1380
|
|
|
1003
1381
|
const { txHash } = await deployer.sendTransaction({
|
|
@@ -1033,6 +1411,13 @@ export const deployL1Contracts = async (
|
|
|
1033
1411
|
logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`);
|
|
1034
1412
|
validateConfig(args);
|
|
1035
1413
|
|
|
1414
|
+
if (args.initialValidators && args.initialValidators.length > 0 && args.existingTokenAddress) {
|
|
1415
|
+
throw new Error(
|
|
1416
|
+
'Cannot deploy with both initialValidators and existingTokenAddress. ' +
|
|
1417
|
+
'Initial validator funding requires minting tokens, which is not possible with an external token.',
|
|
1418
|
+
);
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1036
1421
|
const l1Client = createExtendedL1Client(rpcUrls, account, chain);
|
|
1037
1422
|
|
|
1038
1423
|
// Deploy multicall3 if it does not exist in this network
|
|
@@ -1102,7 +1487,7 @@ export const deployL1Contracts = async (
|
|
|
1102
1487
|
await deployer.waitForDeployments();
|
|
1103
1488
|
|
|
1104
1489
|
// Now that the rollup has been deployed and added to the registry, transfer ownership to governance
|
|
1105
|
-
await handoverToGovernance(
|
|
1490
|
+
const { dateGatedRelayerAddress } = await handoverToGovernance(
|
|
1106
1491
|
l1Client,
|
|
1107
1492
|
deployer,
|
|
1108
1493
|
registryAddress,
|
|
@@ -1112,6 +1497,7 @@ export const deployL1Contracts = async (
|
|
|
1112
1497
|
governanceAddress,
|
|
1113
1498
|
logger,
|
|
1114
1499
|
args.acceleratedTestDeployments,
|
|
1500
|
+
!!args.existingTokenAddress,
|
|
1115
1501
|
);
|
|
1116
1502
|
|
|
1117
1503
|
logger.info(`Handing over to governance complete`);
|
|
@@ -1123,143 +1509,8 @@ export const deployL1Contracts = async (
|
|
|
1123
1509
|
|
|
1124
1510
|
// Write verification data (constructor args + linked libraries) to file for later forge verify
|
|
1125
1511
|
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
|
-
}
|
|
1512
|
+
await generateRollupVerificationRecords(rollup, deployer, args, l1Contracts, l1Client, logger);
|
|
1513
|
+
await writeVerificationJson(deployer, createVerificationJson, chain.id, '', logger);
|
|
1263
1514
|
}
|
|
1264
1515
|
|
|
1265
1516
|
if (isAnvilTestChain(chain.id)) {
|
|
@@ -1269,13 +1520,13 @@ export const deployL1Contracts = async (
|
|
|
1269
1520
|
// Need to get the time
|
|
1270
1521
|
const currentSlot = await rollup.getSlotNumber();
|
|
1271
1522
|
|
|
1272
|
-
if (
|
|
1273
|
-
const ts = Number(await rollup.getTimestampForSlot(
|
|
1523
|
+
if (currentSlot === 0) {
|
|
1524
|
+
const ts = Number(await rollup.getTimestampForSlot(SlotNumber(1)));
|
|
1274
1525
|
await rpcCall('evm_setNextBlockTimestamp', [ts]);
|
|
1275
1526
|
await rpcCall('hardhat_mine', [1]);
|
|
1276
1527
|
const currentSlot = await rollup.getSlotNumber();
|
|
1277
1528
|
|
|
1278
|
-
if (
|
|
1529
|
+
if (currentSlot !== 1) {
|
|
1279
1530
|
throw new Error(`Error jumping time: current slot is ${currentSlot}`);
|
|
1280
1531
|
}
|
|
1281
1532
|
logger.info(`Jumped to slot 1`);
|
|
@@ -1295,6 +1546,7 @@ export const deployL1Contracts = async (
|
|
|
1295
1546
|
stakingAssetHandlerAddress,
|
|
1296
1547
|
zkPassportVerifierAddress,
|
|
1297
1548
|
coinIssuerAddress,
|
|
1549
|
+
dateGatedRelayerAddress,
|
|
1298
1550
|
},
|
|
1299
1551
|
};
|
|
1300
1552
|
};
|
|
@@ -1317,21 +1569,19 @@ export class L1Deployer {
|
|
|
1317
1569
|
this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), { size: 32 }) : undefined;
|
|
1318
1570
|
this.l1TxUtils = createL1TxUtilsFromViemWallet(
|
|
1319
1571
|
this.client,
|
|
1320
|
-
this.logger,
|
|
1321
|
-
|
|
1322
|
-
this.txUtilsConfig,
|
|
1323
|
-
this.acceleratedTestDeployments,
|
|
1572
|
+
{ logger: this.logger, dateProvider },
|
|
1573
|
+
{ ...this.txUtilsConfig, debugMaxGasLimit: acceleratedTestDeployments },
|
|
1324
1574
|
);
|
|
1325
1575
|
}
|
|
1326
1576
|
|
|
1327
1577
|
async deploy<const TAbi extends Abi>(
|
|
1328
1578
|
params: ContractArtifacts<TAbi>,
|
|
1329
1579
|
args?: ContractConstructorArgs<TAbi>,
|
|
1330
|
-
opts: { gasLimit?: bigint } = {},
|
|
1331
|
-
): Promise<EthAddress> {
|
|
1580
|
+
opts: { gasLimit?: bigint; noSimulation?: boolean } = {},
|
|
1581
|
+
): Promise<{ address: EthAddress; existed: boolean }> {
|
|
1332
1582
|
this.logger.debug(`Deploying ${params.name} contract`, { args });
|
|
1333
1583
|
try {
|
|
1334
|
-
const { txHash, address, deployedLibraries } = await deployL1Contract(
|
|
1584
|
+
const { txHash, address, deployedLibraries, existed } = await deployL1Contract(
|
|
1335
1585
|
this.client,
|
|
1336
1586
|
params.contractAbi,
|
|
1337
1587
|
params.contractBytecode,
|
|
@@ -1343,6 +1593,7 @@ export class L1Deployer {
|
|
|
1343
1593
|
l1TxUtils: this.l1TxUtils,
|
|
1344
1594
|
acceleratedTestDeployments: this.acceleratedTestDeployments,
|
|
1345
1595
|
gasLimit: opts.gasLimit,
|
|
1596
|
+
noSimulation: opts.noSimulation,
|
|
1346
1597
|
},
|
|
1347
1598
|
);
|
|
1348
1599
|
if (txHash) {
|
|
@@ -1369,7 +1620,10 @@ export class L1Deployer {
|
|
|
1369
1620
|
libraries: deployedLibraries ?? [],
|
|
1370
1621
|
});
|
|
1371
1622
|
}
|
|
1372
|
-
return
|
|
1623
|
+
return {
|
|
1624
|
+
address,
|
|
1625
|
+
existed,
|
|
1626
|
+
};
|
|
1373
1627
|
} catch (error) {
|
|
1374
1628
|
throw new Error(`Failed to deploy ${params.name}`, { cause: formatViemError(error) });
|
|
1375
1629
|
}
|
|
@@ -1397,13 +1651,16 @@ export class L1Deployer {
|
|
|
1397
1651
|
|
|
1398
1652
|
sendTransaction(
|
|
1399
1653
|
tx: L1TxRequest,
|
|
1400
|
-
options?:
|
|
1654
|
+
options?: L1TxConfig,
|
|
1401
1655
|
): Promise<{ txHash: Hex; gasLimit: bigint; gasPrice: GasPrice }> {
|
|
1402
|
-
return this.l1TxUtils.sendTransaction(tx, options)
|
|
1656
|
+
return this.l1TxUtils.sendTransaction(tx, options).then(({ txHash, state }) => ({
|
|
1657
|
+
txHash,
|
|
1658
|
+
gasLimit: state.gasLimit,
|
|
1659
|
+
gasPrice: state.gasPrice,
|
|
1660
|
+
}));
|
|
1403
1661
|
}
|
|
1404
1662
|
}
|
|
1405
1663
|
|
|
1406
|
-
// docs:start:deployL1Contract
|
|
1407
1664
|
/**
|
|
1408
1665
|
* Helper function to deploy ETH contracts.
|
|
1409
1666
|
* @param walletClient - A viem WalletClient.
|
|
@@ -1426,18 +1683,28 @@ export async function deployL1Contract(
|
|
|
1426
1683
|
l1TxUtils?: L1TxUtils;
|
|
1427
1684
|
gasLimit?: bigint;
|
|
1428
1685
|
acceleratedTestDeployments?: boolean;
|
|
1686
|
+
noSimulation?: boolean;
|
|
1429
1687
|
} = {},
|
|
1430
|
-
): Promise<{
|
|
1688
|
+
): Promise<{
|
|
1689
|
+
address: EthAddress;
|
|
1690
|
+
txHash: Hex | undefined;
|
|
1691
|
+
deployedLibraries?: VerificationLibraryEntry[];
|
|
1692
|
+
existed: boolean;
|
|
1693
|
+
}> {
|
|
1431
1694
|
let txHash: Hex | undefined = undefined;
|
|
1432
1695
|
let resultingAddress: Hex | null | undefined = undefined;
|
|
1433
1696
|
const deployedLibraries: VerificationLibraryEntry[] = [];
|
|
1434
1697
|
|
|
1435
|
-
const { salt: saltFromOpts, libraries, logger, gasLimit, acceleratedTestDeployments } = opts;
|
|
1698
|
+
const { salt: saltFromOpts, libraries, logger, gasLimit, acceleratedTestDeployments, noSimulation } = opts;
|
|
1436
1699
|
let { l1TxUtils } = opts;
|
|
1437
1700
|
|
|
1438
1701
|
if (!l1TxUtils) {
|
|
1439
1702
|
const config = getL1TxUtilsConfigEnvVars();
|
|
1440
|
-
l1TxUtils = createL1TxUtilsFromViemWallet(
|
|
1703
|
+
l1TxUtils = createL1TxUtilsFromViemWallet(
|
|
1704
|
+
extendedClient,
|
|
1705
|
+
{ logger },
|
|
1706
|
+
{ ...config, debugMaxGasLimit: acceleratedTestDeployments },
|
|
1707
|
+
);
|
|
1441
1708
|
}
|
|
1442
1709
|
|
|
1443
1710
|
if (libraries) {
|
|
@@ -1529,17 +1796,21 @@ export async function deployL1Contract(
|
|
|
1529
1796
|
}
|
|
1530
1797
|
}
|
|
1531
1798
|
|
|
1799
|
+
let existed = false;
|
|
1800
|
+
|
|
1532
1801
|
if (saltFromOpts) {
|
|
1533
1802
|
logger?.info(`Deploying contract with salt ${saltFromOpts}`);
|
|
1534
1803
|
const { address, paddedSalt: salt, calldata } = getExpectedAddress(abi, bytecode, args, saltFromOpts);
|
|
1535
1804
|
resultingAddress = address;
|
|
1536
1805
|
const existing = await extendedClient.getCode({ address: resultingAddress });
|
|
1537
1806
|
if (existing === undefined || existing === '0x') {
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1807
|
+
if (!noSimulation) {
|
|
1808
|
+
try {
|
|
1809
|
+
await l1TxUtils.simulate({ to: DEPLOYER_ADDRESS, data: concatHex([salt, calldata]), gas: gasLimit });
|
|
1810
|
+
} catch (err) {
|
|
1811
|
+
logger?.error(`Failed to simulate deployment tx using universal deployer`, err);
|
|
1812
|
+
await l1TxUtils.simulate({ to: null, data: encodeDeployData({ abi, bytecode, args }), gas: gasLimit });
|
|
1813
|
+
}
|
|
1543
1814
|
}
|
|
1544
1815
|
const res = await l1TxUtils.sendTransaction(
|
|
1545
1816
|
{ to: DEPLOYER_ADDRESS, data: concatHex([salt, calldata]) },
|
|
@@ -1550,13 +1821,17 @@ export async function deployL1Contract(
|
|
|
1550
1821
|
logger?.verbose(`Deployed contract with salt ${salt} to address ${resultingAddress} in tx ${txHash}.`);
|
|
1551
1822
|
} else {
|
|
1552
1823
|
logger?.verbose(`Skipping existing deployment of contract with salt ${salt} to address ${resultingAddress}`);
|
|
1824
|
+
existed = true;
|
|
1553
1825
|
}
|
|
1554
1826
|
} else {
|
|
1555
1827
|
const deployData = encodeDeployData({ abi, bytecode, args });
|
|
1556
|
-
const { receipt } = await l1TxUtils.sendAndMonitorTransaction(
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1828
|
+
const { receipt } = await l1TxUtils.sendAndMonitorTransaction(
|
|
1829
|
+
{
|
|
1830
|
+
to: null,
|
|
1831
|
+
data: deployData,
|
|
1832
|
+
},
|
|
1833
|
+
{ gasLimit },
|
|
1834
|
+
);
|
|
1560
1835
|
|
|
1561
1836
|
txHash = receipt.transactionHash;
|
|
1562
1837
|
resultingAddress = receipt.contractAddress;
|
|
@@ -1569,7 +1844,7 @@ export async function deployL1Contract(
|
|
|
1569
1844
|
}
|
|
1570
1845
|
}
|
|
1571
1846
|
|
|
1572
|
-
return { address: EthAddress.fromString(resultingAddress!), txHash, deployedLibraries };
|
|
1847
|
+
return { address: EthAddress.fromString(resultingAddress!), txHash, deployedLibraries, existed };
|
|
1573
1848
|
}
|
|
1574
1849
|
|
|
1575
1850
|
export function getExpectedAddress(
|
|
@@ -1592,5 +1867,3 @@ export function getExpectedAddress(
|
|
|
1592
1867
|
calldata,
|
|
1593
1868
|
};
|
|
1594
1869
|
}
|
|
1595
|
-
|
|
1596
|
-
// docs:end:deployL1Contract
|