@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,55 +1,171 @@
|
|
|
1
1
|
import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/constants';
|
|
2
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import { getActiveNetworkName } from '@aztec/foundation/config';
|
|
3
|
-
import { keccak256String } from '@aztec/foundation/crypto';
|
|
4
|
+
import { keccak256String } from '@aztec/foundation/crypto/keccak';
|
|
4
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
6
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
6
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
7
8
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
8
|
-
import
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import chunk from 'lodash.chunk';
|
|
9
11
|
import { concatHex, encodeAbiParameters, encodeDeployData, encodeFunctionData, getAddress, getContract, getContractAddress, numberToHex, padHex } from 'viem';
|
|
10
12
|
import { foundry } from 'viem/chains';
|
|
11
13
|
import { isAnvilTestChain } from './chain.js';
|
|
12
14
|
import { createExtendedL1Client } from './client.js';
|
|
13
|
-
import { getEntryQueueConfig,
|
|
15
|
+
import { getEntryQueueConfig, getGovernanceConfiguration, getRewardBoostConfig, getRewardConfig, validateConfig } from './config.js';
|
|
14
16
|
import { GSEContract } from './contracts/gse.js';
|
|
15
17
|
import { deployMulticall3 } from './contracts/multicall.js';
|
|
16
18
|
import { RegistryContract } from './contracts/registry.js';
|
|
17
19
|
import { RollupContract, SlashingProposerType } from './contracts/rollup.js';
|
|
18
|
-
import { CoinIssuerArtifact, FeeAssetArtifact, FeeAssetHandlerArtifact, GSEArtifact, GovernanceArtifact, GovernanceProposerArtifact, MultiAdderArtifact, RegisterNewRollupVersionPayloadArtifact, RegistryArtifact, RollupArtifact, SlashFactoryArtifact, StakingAssetArtifact, StakingAssetHandlerArtifact, l1ArtifactsVerifiers, mockVerifiers } from './l1_artifacts.js';
|
|
19
|
-
import { createL1TxUtilsFromViemWallet, getL1TxUtilsConfigEnvVars } from './l1_tx_utils.js';
|
|
20
|
+
import { CoinIssuerArtifact, DateGatedRelayerArtifact, FeeAssetArtifact, FeeAssetHandlerArtifact, GSEArtifact, GovernanceArtifact, GovernanceProposerArtifact, MultiAdderArtifact, RegisterNewRollupVersionPayloadArtifact, RegistryArtifact, RollupArtifact, SlashFactoryArtifact, StakingAssetArtifact, StakingAssetHandlerArtifact, l1ArtifactsVerifiers, mockVerifiers } from './l1_artifacts.js';
|
|
21
|
+
import { createL1TxUtilsFromViemWallet, getL1TxUtilsConfigEnvVars } from './l1_tx_utils/index.js';
|
|
20
22
|
import { formatViemError } from './utils.js';
|
|
21
23
|
import { ZK_PASSPORT_DOMAIN, ZK_PASSPORT_SCOPE, ZK_PASSPORT_VERIFIER_ADDRESS } from './zkPassportVerifierAddress.js';
|
|
22
24
|
export const DEPLOYER_ADDRESS = '0x4e59b44847b379578588920cA78FbF26c0B4956C';
|
|
23
|
-
|
|
25
|
+
// Minimal ERC20 ABI for validation purposes. We only read view methods.
|
|
26
|
+
const ERC20_VALIDATION_ABI = [
|
|
27
|
+
{
|
|
28
|
+
type: 'function',
|
|
29
|
+
name: 'totalSupply',
|
|
30
|
+
stateMutability: 'view',
|
|
31
|
+
inputs: [],
|
|
32
|
+
outputs: [
|
|
33
|
+
{
|
|
34
|
+
name: '',
|
|
35
|
+
type: 'uint256'
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: 'function',
|
|
41
|
+
name: 'name',
|
|
42
|
+
stateMutability: 'view',
|
|
43
|
+
inputs: [],
|
|
44
|
+
outputs: [
|
|
45
|
+
{
|
|
46
|
+
name: '',
|
|
47
|
+
type: 'string'
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: 'function',
|
|
53
|
+
name: 'symbol',
|
|
54
|
+
stateMutability: 'view',
|
|
55
|
+
inputs: [],
|
|
56
|
+
outputs: [
|
|
57
|
+
{
|
|
58
|
+
name: '',
|
|
59
|
+
type: 'string'
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
type: 'function',
|
|
65
|
+
name: 'decimals',
|
|
66
|
+
stateMutability: 'view',
|
|
67
|
+
inputs: [],
|
|
68
|
+
outputs: [
|
|
69
|
+
{
|
|
70
|
+
name: '',
|
|
71
|
+
type: 'uint8'
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
];
|
|
76
|
+
/**
|
|
77
|
+
* Validates that the provided address points to a contract that resembles an ERC20 token.
|
|
78
|
+
* Checks for contract code and attempts common ERC20 view calls.
|
|
79
|
+
* Throws an error if validation fails.
|
|
80
|
+
*/ export async function validateExistingErc20TokenAddress(l1Client, tokenAddress, logger) {
|
|
81
|
+
const addressString = tokenAddress.toString();
|
|
82
|
+
// Ensure there is contract code at the address
|
|
83
|
+
const code = await l1Client.getCode({
|
|
84
|
+
address: addressString
|
|
85
|
+
});
|
|
86
|
+
if (!code || code === '0x') {
|
|
87
|
+
throw new Error(`No contract code found at provided token address ${addressString}`);
|
|
88
|
+
}
|
|
89
|
+
const contract = getContract({
|
|
90
|
+
address: getAddress(addressString),
|
|
91
|
+
abi: ERC20_VALIDATION_ABI,
|
|
92
|
+
client: l1Client
|
|
93
|
+
});
|
|
94
|
+
// Validate all required ERC20 methods in parallel
|
|
95
|
+
const checks = [
|
|
96
|
+
contract.read.totalSupply().then((total)=>typeof total === 'bigint'),
|
|
97
|
+
contract.read.name().then(()=>true),
|
|
98
|
+
contract.read.symbol().then(()=>true),
|
|
99
|
+
contract.read.decimals().then((dec)=>typeof dec === 'number' || typeof dec === 'bigint')
|
|
100
|
+
];
|
|
101
|
+
const results = await Promise.allSettled(checks);
|
|
102
|
+
const failedChecks = results.filter((result)=>result.status === 'rejected' || result.value !== true);
|
|
103
|
+
if (failedChecks.length > 0) {
|
|
104
|
+
throw new Error(`Address ${addressString} does not appear to implement ERC20 view methods`);
|
|
105
|
+
}
|
|
106
|
+
logger.verbose(`Validated existing token at ${addressString} appears to be ERC20-compatible`);
|
|
107
|
+
}
|
|
24
108
|
export const deploySharedContracts = async (l1Client, deployer, args, logger)=>{
|
|
25
|
-
|
|
109
|
+
const networkName = getActiveNetworkName();
|
|
110
|
+
logger.info(`Deploying shared contracts for network configuration: ${networkName}`);
|
|
26
111
|
const txHashes = [];
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
l1Client.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
112
|
+
let feeAssetAddress;
|
|
113
|
+
let stakingAssetAddress;
|
|
114
|
+
if (args.existingTokenAddress) {
|
|
115
|
+
await validateExistingErc20TokenAddress(l1Client, args.existingTokenAddress, logger);
|
|
116
|
+
feeAssetAddress = args.existingTokenAddress;
|
|
117
|
+
stakingAssetAddress = args.existingTokenAddress;
|
|
118
|
+
logger.verbose(`Using existing token for fee and staking assets at ${args.existingTokenAddress}`);
|
|
119
|
+
} else {
|
|
120
|
+
const deployedFee = await deployer.deploy(FeeAssetArtifact, [
|
|
121
|
+
'FeeJuice',
|
|
122
|
+
'FEE',
|
|
123
|
+
l1Client.account.address
|
|
124
|
+
]);
|
|
125
|
+
feeAssetAddress = deployedFee.address;
|
|
126
|
+
logger.verbose(`Deployed Fee Asset at ${feeAssetAddress}`);
|
|
127
|
+
// Mint a tiny bit of tokens to satisfy coin-issuer constraints
|
|
128
|
+
const { txHash } = await deployer.sendTransaction({
|
|
129
|
+
to: feeAssetAddress.toString(),
|
|
130
|
+
data: encodeFunctionData({
|
|
131
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
132
|
+
functionName: 'mint',
|
|
133
|
+
args: [
|
|
134
|
+
l1Client.account.address,
|
|
135
|
+
1n * 10n ** 18n
|
|
136
|
+
]
|
|
137
|
+
})
|
|
138
|
+
}, {
|
|
139
|
+
// contract may not have been deployed yet (CREATE2 returns address before mining),
|
|
140
|
+
// which causes gas estimation to fail. Hardcode to 100k which is plenty for ERC20 mint.
|
|
141
|
+
gasLimit: 100_000n
|
|
142
|
+
});
|
|
143
|
+
await l1Client.waitForTransactionReceipt({
|
|
144
|
+
hash: txHash
|
|
145
|
+
});
|
|
146
|
+
logger.verbose(`Minted tiny bit of tokens to satisfy coin-issuer constraints in ${txHash}`);
|
|
147
|
+
const deployedStaking = await deployer.deploy(StakingAssetArtifact, [
|
|
148
|
+
'Staking',
|
|
149
|
+
'STK',
|
|
150
|
+
l1Client.account.address
|
|
151
|
+
]);
|
|
152
|
+
stakingAssetAddress = deployedStaking.address;
|
|
153
|
+
logger.verbose(`Deployed Staking Asset at ${stakingAssetAddress}`);
|
|
154
|
+
await deployer.waitForDeployments();
|
|
155
|
+
}
|
|
156
|
+
const gseAddress = (await deployer.deploy(GSEArtifact, [
|
|
41
157
|
l1Client.account.address,
|
|
42
158
|
stakingAssetAddress.toString(),
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
]);
|
|
159
|
+
args.activationThreshold,
|
|
160
|
+
args.ejectionThreshold
|
|
161
|
+
])).address;
|
|
46
162
|
logger.verbose(`Deployed GSE at ${gseAddress}`);
|
|
47
|
-
const registryAddress = await deployer.deploy(RegistryArtifact, [
|
|
163
|
+
const { address: registryAddress } = await deployer.deploy(RegistryArtifact, [
|
|
48
164
|
l1Client.account.address,
|
|
49
165
|
feeAssetAddress.toString()
|
|
50
166
|
]);
|
|
51
167
|
logger.verbose(`Deployed Registry at ${registryAddress}`);
|
|
52
|
-
const governanceProposerAddress = await deployer.deploy(GovernanceProposerArtifact, [
|
|
168
|
+
const { address: governanceProposerAddress } = await deployer.deploy(GovernanceProposerArtifact, [
|
|
53
169
|
registryAddress.toString(),
|
|
54
170
|
gseAddress.toString(),
|
|
55
171
|
BigInt(args.governanceProposerQuorum ?? args.governanceProposerRoundSize / 2 + 1),
|
|
@@ -58,7 +174,7 @@ export const deploySharedContracts = async (l1Client, deployer, args, logger)=>{
|
|
|
58
174
|
logger.verbose(`Deployed GovernanceProposer at ${governanceProposerAddress}`);
|
|
59
175
|
// @note @LHerskind the assets are expected to be the same at some point, but for better
|
|
60
176
|
// configurability they are different for now.
|
|
61
|
-
const governanceAddress = await deployer.deploy(GovernanceArtifact, [
|
|
177
|
+
const { address: governanceAddress } = await deployer.deploy(GovernanceArtifact, [
|
|
62
178
|
stakingAssetAddress.toString(),
|
|
63
179
|
governanceProposerAddress.toString(),
|
|
64
180
|
gseAddress.toString(),
|
|
@@ -98,11 +214,16 @@ export const deploySharedContracts = async (l1Client, deployer, args, logger)=>{
|
|
|
98
214
|
logger.verbose(`Set governance on GSE in ${txHash}`);
|
|
99
215
|
txHashes.push(txHash);
|
|
100
216
|
}
|
|
101
|
-
|
|
217
|
+
logger.verbose(`Waiting for deployments to complete`);
|
|
218
|
+
await deployer.waitForDeployments();
|
|
219
|
+
const coinIssuerAddress = (await deployer.deploy(CoinIssuerArtifact, [
|
|
102
220
|
feeAssetAddress.toString(),
|
|
103
|
-
|
|
221
|
+
2n * 10n ** 17n,
|
|
104
222
|
l1Client.account.address
|
|
105
|
-
]
|
|
223
|
+
], {
|
|
224
|
+
gasLimit: 1_000_000n,
|
|
225
|
+
noSimulation: true
|
|
226
|
+
})).address;
|
|
106
227
|
logger.verbose(`Deployed CoinIssuer at ${coinIssuerAddress}`);
|
|
107
228
|
logger.verbose(`Waiting for deployments to complete`);
|
|
108
229
|
await deployer.waitForDeployments();
|
|
@@ -110,16 +231,17 @@ export const deploySharedContracts = async (l1Client, deployer, args, logger)=>{
|
|
|
110
231
|
let feeAssetHandlerAddress = undefined;
|
|
111
232
|
let stakingAssetHandlerAddress = undefined;
|
|
112
233
|
let zkPassportVerifierAddress = undefined;
|
|
113
|
-
// Only if not on mainnet will we deploy the handlers
|
|
114
|
-
if (l1Client.chain.id !== 1) {
|
|
115
|
-
/* -------------------------------------------------------------------------- */ /* CHEAT CODES START HERE */ /* -------------------------------------------------------------------------- */
|
|
234
|
+
// Only if not on mainnet will we deploy the handlers, and only when we control the token
|
|
235
|
+
if (l1Client.chain.id !== 1 && !args.existingTokenAddress) {
|
|
236
|
+
/* -------------------------------------------------------------------------- */ /* CHEAT CODES START HERE */ /* -------------------------------------------------------------------------- */ const deployedFeeAssetHandler = await deployer.deploy(FeeAssetHandlerArtifact, [
|
|
116
237
|
l1Client.account.address,
|
|
117
238
|
feeAssetAddress.toString(),
|
|
118
239
|
BigInt(1000n * 10n ** 18n)
|
|
119
240
|
]);
|
|
241
|
+
feeAssetHandlerAddress = deployedFeeAssetHandler.address;
|
|
120
242
|
logger.verbose(`Deployed FeeAssetHandler at ${feeAssetHandlerAddress}`);
|
|
121
|
-
// Only
|
|
122
|
-
if (
|
|
243
|
+
// Only add as minter if this is a new deployment (not reusing existing handler from failed previous run)
|
|
244
|
+
if (!deployedFeeAssetHandler.existed) {
|
|
123
245
|
const { txHash } = await deployer.sendTransaction({
|
|
124
246
|
to: feeAssetAddress.toString(),
|
|
125
247
|
data: encodeFunctionData({
|
|
@@ -147,6 +269,7 @@ export const deploySharedContracts = async (l1Client, deployer, args, logger)=>{
|
|
|
147
269
|
stakingAsset: stakingAssetAddress.toString(),
|
|
148
270
|
registry: registryAddress.toString(),
|
|
149
271
|
withdrawer: AMIN.toString(),
|
|
272
|
+
validatorsToFlush: 16n,
|
|
150
273
|
mintInterval: BigInt(60 * 60 * 24),
|
|
151
274
|
depositsPerMint: BigInt(10),
|
|
152
275
|
depositMerkleRoot: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
@@ -161,9 +284,9 @@ export const deploySharedContracts = async (l1Client, deployer, args, logger)=>{
|
|
|
161
284
|
skipBindCheck: args.zkPassportArgs?.mockZkPassportVerifier ?? false,
|
|
162
285
|
skipMerkleCheck: true
|
|
163
286
|
};
|
|
164
|
-
stakingAssetHandlerAddress = await deployer.deploy(StakingAssetHandlerArtifact, [
|
|
287
|
+
stakingAssetHandlerAddress = (await deployer.deploy(StakingAssetHandlerArtifact, [
|
|
165
288
|
stakingAssetHandlerDeployArgs
|
|
166
|
-
]);
|
|
289
|
+
])).address;
|
|
167
290
|
logger.verbose(`Deployed StakingAssetHandler at ${stakingAssetHandlerAddress}`);
|
|
168
291
|
const { txHash: stakingMinterTxHash } = await deployer.sendTransaction({
|
|
169
292
|
to: stakingAssetAddress.toString(),
|
|
@@ -187,20 +310,24 @@ export const deploySharedContracts = async (l1Client, deployer, args, logger)=>{
|
|
|
187
310
|
logger.verbose(`Deployed shared contracts`);
|
|
188
311
|
const registry = new RegistryContract(l1Client, registryAddress);
|
|
189
312
|
/* -------------------------------------------------------------------------- */ /* FUND REWARD DISTRIBUTOR START */ /* -------------------------------------------------------------------------- */ const rewardDistributorAddress = await registry.getRewardDistributor();
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
313
|
+
if (!args.existingTokenAddress) {
|
|
314
|
+
const checkpointReward = getRewardConfig(networkName).checkpointReward;
|
|
315
|
+
const funding = checkpointReward * 200000n;
|
|
316
|
+
const { txHash: fundRewardDistributorTxHash } = await deployer.sendTransaction({
|
|
317
|
+
to: feeAssetAddress.toString(),
|
|
318
|
+
data: encodeFunctionData({
|
|
319
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
320
|
+
functionName: 'mint',
|
|
321
|
+
args: [
|
|
322
|
+
rewardDistributorAddress.toString(),
|
|
323
|
+
funding
|
|
324
|
+
]
|
|
325
|
+
})
|
|
326
|
+
});
|
|
327
|
+
logger.verbose(`Funded reward distributor with ${funding} fee asset in ${fundRewardDistributorTxHash}`);
|
|
328
|
+
} else {
|
|
329
|
+
logger.verbose(`Skipping reward distributor funding as existing token is provided`);
|
|
330
|
+
}
|
|
204
331
|
/* -------------------------------------------------------------------------- */ /* FUND REWARD DISTRIBUTOR STOP */ /* -------------------------------------------------------------------------- */ return {
|
|
205
332
|
feeAssetAddress,
|
|
206
333
|
feeAssetHandlerAddress,
|
|
@@ -217,7 +344,7 @@ export const deploySharedContracts = async (l1Client, deployer, args, logger)=>{
|
|
|
217
344
|
};
|
|
218
345
|
const getZkPassportVerifierAddress = async (deployer, args)=>{
|
|
219
346
|
if (args.zkPassportArgs?.mockZkPassportVerifier) {
|
|
220
|
-
return await deployer.deploy(mockVerifiers.mockZkPassportVerifier);
|
|
347
|
+
return (await deployer.deploy(mockVerifiers.mockZkPassportVerifier)).address;
|
|
221
348
|
}
|
|
222
349
|
return ZK_PASSPORT_VERIFIER_ADDRESS;
|
|
223
350
|
};
|
|
@@ -233,6 +360,224 @@ const getZkPassportVerifierAddress = async (deployer, args)=>{
|
|
|
233
360
|
scope
|
|
234
361
|
];
|
|
235
362
|
};
|
|
363
|
+
/**
|
|
364
|
+
* Generates verification records for a deployed rollup and its associated contracts (Inbox, Outbox, Slasher, etc).
|
|
365
|
+
* @param rollup - The deployed rollup contract.
|
|
366
|
+
* @param deployer - The L1 deployer instance.
|
|
367
|
+
* @param args - The deployment arguments used for the rollup.
|
|
368
|
+
* @param addresses - The L1 contract addresses.
|
|
369
|
+
* @param extendedClient - The extended viem wallet client.
|
|
370
|
+
* @param logger - The logger.
|
|
371
|
+
*/ async function generateRollupVerificationRecords(rollup, deployer, args, addresses, extendedClient, logger) {
|
|
372
|
+
try {
|
|
373
|
+
// Add Inbox / Outbox verification records (constructor args are created inside RollupCore)
|
|
374
|
+
const rollupAddr = rollup.address;
|
|
375
|
+
const rollupAddresses = await rollup.getRollupAddresses();
|
|
376
|
+
const inboxAddr = rollupAddresses.inboxAddress.toString();
|
|
377
|
+
const outboxAddr = rollupAddresses.outboxAddress.toString();
|
|
378
|
+
const feeAsset = rollupAddresses.feeJuiceAddress.toString();
|
|
379
|
+
const version = await rollup.getVersion();
|
|
380
|
+
const inboxCtor = encodeAbiParameters([
|
|
381
|
+
{
|
|
382
|
+
type: 'address'
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
type: 'address'
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
type: 'uint256'
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
type: 'uint256'
|
|
392
|
+
}
|
|
393
|
+
], [
|
|
394
|
+
rollupAddr,
|
|
395
|
+
feeAsset,
|
|
396
|
+
version,
|
|
397
|
+
BigInt(L1_TO_L2_MSG_SUBTREE_HEIGHT)
|
|
398
|
+
]);
|
|
399
|
+
const outboxCtor = encodeAbiParameters([
|
|
400
|
+
{
|
|
401
|
+
type: 'address'
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
type: 'uint256'
|
|
405
|
+
}
|
|
406
|
+
], [
|
|
407
|
+
rollupAddr,
|
|
408
|
+
version
|
|
409
|
+
]);
|
|
410
|
+
deployer.verificationRecords.push({
|
|
411
|
+
name: 'Inbox',
|
|
412
|
+
address: inboxAddr,
|
|
413
|
+
constructorArgsHex: inboxCtor,
|
|
414
|
+
libraries: []
|
|
415
|
+
}, {
|
|
416
|
+
name: 'Outbox',
|
|
417
|
+
address: outboxAddr,
|
|
418
|
+
constructorArgsHex: outboxCtor,
|
|
419
|
+
libraries: []
|
|
420
|
+
});
|
|
421
|
+
// Include Slasher and SlashingProposer (if deployed) in verification data
|
|
422
|
+
try {
|
|
423
|
+
const slasherAddrHex = await rollup.getSlasherAddress();
|
|
424
|
+
const slasherAddr = EthAddress.fromString(slasherAddrHex);
|
|
425
|
+
if (!slasherAddr.isZero()) {
|
|
426
|
+
// Slasher constructor: (address _vetoer, address _governance)
|
|
427
|
+
const slasherCtor = encodeAbiParameters([
|
|
428
|
+
{
|
|
429
|
+
type: 'address'
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
type: 'address'
|
|
433
|
+
}
|
|
434
|
+
], [
|
|
435
|
+
args.slashingVetoer.toString(),
|
|
436
|
+
extendedClient.account.address
|
|
437
|
+
]);
|
|
438
|
+
deployer.verificationRecords.push({
|
|
439
|
+
name: 'Slasher',
|
|
440
|
+
address: slasherAddr.toString(),
|
|
441
|
+
constructorArgsHex: slasherCtor,
|
|
442
|
+
libraries: []
|
|
443
|
+
});
|
|
444
|
+
// Proposer address is stored in Slasher.PROPOSER()
|
|
445
|
+
const proposerAddr = (await rollup.getSlashingProposerAddress()).toString();
|
|
446
|
+
// Compute constructor args matching deployment path in RollupCore
|
|
447
|
+
const computedRoundSize = BigInt(args.slashingRoundSizeInEpochs * args.aztecEpochDuration);
|
|
448
|
+
const computedQuorum = BigInt(args.slashingQuorum ?? args.slashingRoundSizeInEpochs * args.aztecEpochDuration / 2 + 1);
|
|
449
|
+
const lifetimeInRounds = BigInt(args.slashingLifetimeInRounds);
|
|
450
|
+
const executionDelayInRounds = BigInt(args.slashingExecutionDelayInRounds);
|
|
451
|
+
if (args.slasherFlavor === 'tally') {
|
|
452
|
+
const slashAmounts = [
|
|
453
|
+
args.slashAmountSmall,
|
|
454
|
+
args.slashAmountMedium,
|
|
455
|
+
args.slashAmountLarge
|
|
456
|
+
];
|
|
457
|
+
const committeeSize = BigInt(args.aztecTargetCommitteeSize);
|
|
458
|
+
const epochDuration = BigInt(args.aztecEpochDuration);
|
|
459
|
+
const slashOffsetInRounds = BigInt(args.slashingOffsetInRounds);
|
|
460
|
+
const proposerCtor = encodeAbiParameters([
|
|
461
|
+
{
|
|
462
|
+
type: 'address'
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
type: 'address'
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
type: 'uint256'
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
type: 'uint256'
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
type: 'uint256'
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
type: 'uint256'
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
type: 'uint256[3]'
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
type: 'uint256'
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
type: 'uint256'
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
type: 'uint256'
|
|
490
|
+
}
|
|
491
|
+
], [
|
|
492
|
+
rollup.address,
|
|
493
|
+
slasherAddr.toString(),
|
|
494
|
+
computedQuorum,
|
|
495
|
+
computedRoundSize,
|
|
496
|
+
lifetimeInRounds,
|
|
497
|
+
executionDelayInRounds,
|
|
498
|
+
slashAmounts,
|
|
499
|
+
committeeSize,
|
|
500
|
+
epochDuration,
|
|
501
|
+
slashOffsetInRounds
|
|
502
|
+
]);
|
|
503
|
+
deployer.verificationRecords.push({
|
|
504
|
+
name: 'TallySlashingProposer',
|
|
505
|
+
address: proposerAddr,
|
|
506
|
+
constructorArgsHex: proposerCtor,
|
|
507
|
+
libraries: []
|
|
508
|
+
});
|
|
509
|
+
} else if (args.slasherFlavor === 'empire') {
|
|
510
|
+
const proposerCtor = encodeAbiParameters([
|
|
511
|
+
{
|
|
512
|
+
type: 'address'
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
type: 'address'
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
type: 'uint256'
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
type: 'uint256'
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
type: 'uint256'
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
type: 'uint256'
|
|
528
|
+
}
|
|
529
|
+
], [
|
|
530
|
+
rollup.address,
|
|
531
|
+
slasherAddr.toString(),
|
|
532
|
+
computedQuorum,
|
|
533
|
+
computedRoundSize,
|
|
534
|
+
lifetimeInRounds,
|
|
535
|
+
executionDelayInRounds
|
|
536
|
+
]);
|
|
537
|
+
deployer.verificationRecords.push({
|
|
538
|
+
name: 'EmpireSlashingProposer',
|
|
539
|
+
address: proposerAddr,
|
|
540
|
+
constructorArgsHex: proposerCtor,
|
|
541
|
+
libraries: []
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
} catch (e) {
|
|
546
|
+
logger.warn(`Failed to add Slasher/Proposer verification records: ${String(e)}`);
|
|
547
|
+
}
|
|
548
|
+
} catch (e) {
|
|
549
|
+
throw new Error(`Failed to generate rollup verification records: ${String(e)}`);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Writes verification records to a JSON file for later forge verify.
|
|
554
|
+
* @param deployer - The L1 deployer containing verification records.
|
|
555
|
+
* @param outputDirectory - The directory to write the verification file to.
|
|
556
|
+
* @param chainId - The chain ID.
|
|
557
|
+
* @param filenameSuffix - Optional suffix for the filename (e.g., 'upgrade').
|
|
558
|
+
* @param logger - The logger.
|
|
559
|
+
*/ async function writeVerificationJson(deployer, outputDirectory, chainId, filenameSuffix = '', logger) {
|
|
560
|
+
try {
|
|
561
|
+
const date = new Date();
|
|
562
|
+
const formattedDate = date.toISOString().slice(2, 19).replace(/[-T:]/g, '');
|
|
563
|
+
// Ensure the verification output directory exists
|
|
564
|
+
await fs.promises.mkdir(outputDirectory, {
|
|
565
|
+
recursive: true
|
|
566
|
+
});
|
|
567
|
+
const suffix = filenameSuffix ? `-${filenameSuffix}` : '';
|
|
568
|
+
const verificationOutputPath = `${outputDirectory}/l1-verify${suffix}-${chainId}-${formattedDate.slice(0, 6)}-${formattedDate.slice(6)}.json`;
|
|
569
|
+
const networkName = getActiveNetworkName();
|
|
570
|
+
const verificationData = {
|
|
571
|
+
chainId: chainId,
|
|
572
|
+
network: networkName,
|
|
573
|
+
records: deployer.verificationRecords
|
|
574
|
+
};
|
|
575
|
+
await fs.promises.writeFile(verificationOutputPath, JSON.stringify(verificationData, null, 2));
|
|
576
|
+
logger.info(`Wrote L1 verification data to ${verificationOutputPath}`);
|
|
577
|
+
} catch (e) {
|
|
578
|
+
logger.warn(`Failed to write L1 verification data file: ${String(e)}`);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
236
581
|
/**
|
|
237
582
|
* Deploys a new rollup, using the existing canonical version to derive certain values (addresses of assets etc).
|
|
238
583
|
* @param clients - The L1 clients.
|
|
@@ -240,28 +585,34 @@ const getZkPassportVerifierAddress = async (deployer, args)=>{
|
|
|
240
585
|
* @param registryAddress - The address of the registry.
|
|
241
586
|
* @param logger - The logger.
|
|
242
587
|
* @param txUtilsConfig - The L1 tx utils config.
|
|
243
|
-
|
|
244
|
-
|
|
588
|
+
* @param createVerificationJson - Optional path to write verification data for forge verify.
|
|
589
|
+
*/ export const deployRollupForUpgrade = async (extendedClient, args, registryAddress, logger, txUtilsConfig, createVerificationJson = false)=>{
|
|
590
|
+
const deployer = new L1Deployer(extendedClient, args.salt, undefined, args.acceleratedTestDeployments, logger, txUtilsConfig, !!createVerificationJson);
|
|
245
591
|
const addresses = await RegistryContract.collectAddresses(extendedClient, registryAddress, 'canonical');
|
|
246
592
|
const { rollup, slashFactoryAddress } = await deployRollup(extendedClient, deployer, args, addresses, logger);
|
|
247
593
|
await deployer.waitForDeployments();
|
|
594
|
+
// Write verification data (constructor args + linked libraries) to file for later forge verify
|
|
595
|
+
if (createVerificationJson) {
|
|
596
|
+
await generateRollupVerificationRecords(rollup, deployer, args, addresses, extendedClient, logger);
|
|
597
|
+
await writeVerificationJson(deployer, createVerificationJson, extendedClient.chain.id, 'upgrade', logger);
|
|
598
|
+
}
|
|
248
599
|
return {
|
|
249
600
|
rollup,
|
|
250
601
|
slashFactoryAddress
|
|
251
602
|
};
|
|
252
603
|
};
|
|
253
604
|
export const deploySlashFactory = async (deployer, rollupAddress, logger)=>{
|
|
254
|
-
const slashFactoryAddress = await deployer.deploy(SlashFactoryArtifact, [
|
|
605
|
+
const slashFactoryAddress = (await deployer.deploy(SlashFactoryArtifact, [
|
|
255
606
|
rollupAddress
|
|
256
|
-
]);
|
|
607
|
+
])).address;
|
|
257
608
|
logger.verbose(`Deployed SlashFactory at ${slashFactoryAddress}`);
|
|
258
609
|
return slashFactoryAddress;
|
|
259
610
|
};
|
|
260
611
|
export const deployUpgradePayload = async (deployer, addresses)=>{
|
|
261
|
-
const payloadAddress = await deployer.deploy(RegisterNewRollupVersionPayloadArtifact, [
|
|
612
|
+
const payloadAddress = (await deployer.deploy(RegisterNewRollupVersionPayloadArtifact, [
|
|
262
613
|
addresses.registryAddress.toString(),
|
|
263
614
|
addresses.rollupAddress.toString()
|
|
264
|
-
]);
|
|
615
|
+
])).address;
|
|
265
616
|
return payloadAddress;
|
|
266
617
|
};
|
|
267
618
|
function slasherFlavorToSolidityEnum(flavor) {
|
|
@@ -285,14 +636,15 @@ function slasherFlavorToSolidityEnum(flavor) {
|
|
|
285
636
|
if (!addresses.gseAddress) {
|
|
286
637
|
throw new Error('GSE address is required when deploying');
|
|
287
638
|
}
|
|
639
|
+
const networkName = getActiveNetworkName();
|
|
288
640
|
logger.info(`Deploying rollup using network configuration: ${networkName}`);
|
|
289
641
|
const txHashes = [];
|
|
290
642
|
let epochProofVerifier = EthAddress.ZERO;
|
|
291
643
|
if (args.realVerifier) {
|
|
292
|
-
epochProofVerifier = await deployer.deploy(l1ArtifactsVerifiers.honkVerifier);
|
|
644
|
+
epochProofVerifier = (await deployer.deploy(l1ArtifactsVerifiers.honkVerifier)).address;
|
|
293
645
|
logger.verbose(`Rollup will use the real verifier at ${epochProofVerifier}`);
|
|
294
646
|
} else {
|
|
295
|
-
epochProofVerifier = await deployer.deploy(mockVerifiers.mockVerifier);
|
|
647
|
+
epochProofVerifier = (await deployer.deploy(mockVerifiers.mockVerifier)).address;
|
|
296
648
|
logger.verbose(`Rollup will use the mock verifier at ${epochProofVerifier}`);
|
|
297
649
|
}
|
|
298
650
|
const rewardConfig = {
|
|
@@ -303,6 +655,8 @@ function slasherFlavorToSolidityEnum(flavor) {
|
|
|
303
655
|
aztecSlotDuration: BigInt(args.aztecSlotDuration),
|
|
304
656
|
aztecEpochDuration: BigInt(args.aztecEpochDuration),
|
|
305
657
|
targetCommitteeSize: BigInt(args.aztecTargetCommitteeSize),
|
|
658
|
+
lagInEpochsForValidatorSet: BigInt(args.lagInEpochsForValidatorSet),
|
|
659
|
+
lagInEpochsForRandao: BigInt(args.lagInEpochsForRandao),
|
|
306
660
|
aztecProofSubmissionEpochs: BigInt(args.aztecProofSubmissionEpochs),
|
|
307
661
|
slashingQuorum: BigInt(args.slashingQuorum ?? args.slashingRoundSizeInEpochs * args.aztecEpochDuration / 2 + 1),
|
|
308
662
|
slashingRoundSize: BigInt(args.slashingRoundSizeInEpochs * args.aztecEpochDuration),
|
|
@@ -313,7 +667,7 @@ function slasherFlavorToSolidityEnum(flavor) {
|
|
|
313
667
|
provingCostPerMana: args.provingCostPerMana,
|
|
314
668
|
rewardConfig: rewardConfig,
|
|
315
669
|
version: 0,
|
|
316
|
-
rewardBoostConfig: getRewardBoostConfig(
|
|
670
|
+
rewardBoostConfig: getRewardBoostConfig(),
|
|
317
671
|
stakingQueueConfig: getEntryQueueConfig(networkName),
|
|
318
672
|
exitDelaySeconds: BigInt(args.exitDelaySeconds),
|
|
319
673
|
slasherFlavor: slasherFlavorToSolidityEnum(args.slasherFlavor),
|
|
@@ -322,11 +676,14 @@ function slasherFlavorToSolidityEnum(flavor) {
|
|
|
322
676
|
args.slashAmountSmall,
|
|
323
677
|
args.slashAmountMedium,
|
|
324
678
|
args.slashAmountLarge
|
|
325
|
-
]
|
|
679
|
+
],
|
|
680
|
+
localEjectionThreshold: args.localEjectionThreshold,
|
|
681
|
+
slashingDisableDuration: BigInt(args.slashingDisableDuration ?? 0n),
|
|
682
|
+
earliestRewardsClaimableTimestamp: 0n
|
|
326
683
|
};
|
|
327
684
|
const genesisStateArgs = {
|
|
328
685
|
vkTreeRoot: args.vkTreeRoot.toString(),
|
|
329
|
-
|
|
686
|
+
protocolContractsHash: args.protocolContractsHash.toString(),
|
|
330
687
|
genesisArchiveRoot: args.genesisArchiveRoot.toString()
|
|
331
688
|
};
|
|
332
689
|
// Until there is an actual chain-id for the version, we will just draw a random value.
|
|
@@ -345,33 +702,38 @@ function slasherFlavorToSolidityEnum(flavor) {
|
|
|
345
702
|
genesisStateArgs,
|
|
346
703
|
rollupConfigArgs
|
|
347
704
|
];
|
|
348
|
-
const rollupAddress = await deployer.deploy(RollupArtifact, rollupArgs, {
|
|
705
|
+
const { address: rollupAddress, existed: rollupExisted } = await deployer.deploy(RollupArtifact, rollupArgs, {
|
|
349
706
|
gasLimit: 15_000_000n
|
|
350
707
|
});
|
|
351
|
-
logger.verbose(`Deployed Rollup at ${rollupAddress}`, rollupConfigArgs);
|
|
708
|
+
logger.verbose(`Deployed Rollup at ${rollupAddress}, already existed: ${rollupExisted}`, rollupConfigArgs);
|
|
352
709
|
const rollupContract = new RollupContract(extendedClient, rollupAddress);
|
|
353
710
|
await deployer.waitForDeployments();
|
|
354
711
|
logger.verbose(`All core contracts have been deployed`);
|
|
355
712
|
if (args.feeJuicePortalInitialBalance && args.feeJuicePortalInitialBalance > 0n) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
to
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
args
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
713
|
+
// Skip funding when using an external token, as we likely don't have mint permissions
|
|
714
|
+
if (!('existingTokenAddress' in args) || !args.existingTokenAddress) {
|
|
715
|
+
const feeJuicePortalAddress = await rollupContract.getFeeJuicePortal();
|
|
716
|
+
// In fast mode, use the L1TxUtils to send transactions with nonce management
|
|
717
|
+
const { txHash: mintTxHash } = await deployer.sendTransaction({
|
|
718
|
+
to: addresses.feeJuiceAddress.toString(),
|
|
719
|
+
data: encodeFunctionData({
|
|
720
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
721
|
+
functionName: 'mint',
|
|
722
|
+
args: [
|
|
723
|
+
feeJuicePortalAddress.toString(),
|
|
724
|
+
args.feeJuicePortalInitialBalance
|
|
725
|
+
]
|
|
726
|
+
})
|
|
727
|
+
});
|
|
728
|
+
logger.verbose(`Funding fee juice portal with ${args.feeJuicePortalInitialBalance} fee juice in ${mintTxHash} (accelerated test deployments)`);
|
|
729
|
+
txHashes.push(mintTxHash);
|
|
730
|
+
} else {
|
|
731
|
+
logger.verbose('Skipping fee juice portal funding due to external token usage');
|
|
732
|
+
}
|
|
371
733
|
}
|
|
372
|
-
const slashFactoryAddress = await deployer.deploy(SlashFactoryArtifact, [
|
|
734
|
+
const slashFactoryAddress = (await deployer.deploy(SlashFactoryArtifact, [
|
|
373
735
|
rollupAddress.toString()
|
|
374
|
-
]);
|
|
736
|
+
])).address;
|
|
375
737
|
logger.verbose(`Deployed SlashFactory at ${slashFactoryAddress}`);
|
|
376
738
|
// We need to call a function on the registry to set the various contract addresses.
|
|
377
739
|
const registryContract = getContract({
|
|
@@ -435,7 +797,11 @@ function slasherFlavorToSolidityEnum(flavor) {
|
|
|
435
797
|
} else {
|
|
436
798
|
logger.verbose(`Not the owner of the gse, skipping rollup addition`);
|
|
437
799
|
}
|
|
438
|
-
|
|
800
|
+
const activeAttestorCount = await rollupContract.getActiveAttesterCount();
|
|
801
|
+
const queuedAttestorCount = await rollupContract.getEntryQueueLength();
|
|
802
|
+
logger.info(`Rollup has ${activeAttestorCount} active attestors and ${queuedAttestorCount} queued attestors`);
|
|
803
|
+
const shouldAddValidators = activeAttestorCount === 0n && queuedAttestorCount === 0n;
|
|
804
|
+
if (args.initialValidators && shouldAddValidators && await gseContract.read.isRollupRegistered([
|
|
439
805
|
rollupContract.address
|
|
440
806
|
])) {
|
|
441
807
|
await addMultipleValidators(extendedClient, deployer, addresses.gseAddress.toString(), rollupAddress.toString(), addresses.stakingAssetAddress.toString(), args.initialValidators, args.acceleratedTestDeployments, logger);
|
|
@@ -467,7 +833,7 @@ function slasherFlavorToSolidityEnum(flavor) {
|
|
|
467
833
|
slashFactoryAddress
|
|
468
834
|
};
|
|
469
835
|
};
|
|
470
|
-
export const handoverToGovernance = async (extendedClient, deployer, registryAddress, gseAddress, coinIssuerAddress, feeAssetAddress, governanceAddress, logger, acceleratedTestDeployments)=>{
|
|
836
|
+
export const handoverToGovernance = async (extendedClient, deployer, registryAddress, gseAddress, coinIssuerAddress, feeAssetAddress, governanceAddress, logger, acceleratedTestDeployments, useExternalToken = false)=>{
|
|
471
837
|
// We need to call a function on the registry to set the various contract addresses.
|
|
472
838
|
const registryContract = getContract({
|
|
473
839
|
address: getAddress(registryAddress.toString()),
|
|
@@ -522,7 +888,7 @@ export const handoverToGovernance = async (extendedClient, deployer, registryAdd
|
|
|
522
888
|
logger.verbose(`Transferring the ownership of the gse contract at ${gseAddress} to the Governance ${governanceAddress} in tx ${transferOwnershipTxHash}`);
|
|
523
889
|
txHashes.push(transferOwnershipTxHash);
|
|
524
890
|
}
|
|
525
|
-
if (acceleratedTestDeployments || await feeAsset.read.owner() !== coinIssuerAddress.toString()) {
|
|
891
|
+
if (!useExternalToken && (acceleratedTestDeployments || await feeAsset.read.owner() !== coinIssuerAddress.toString())) {
|
|
526
892
|
const { txHash } = await deployer.sendTransaction({
|
|
527
893
|
to: feeAssetAddress.toString(),
|
|
528
894
|
data: encodeFunctionData({
|
|
@@ -548,20 +914,27 @@ export const handoverToGovernance = async (extendedClient, deployer, registryAdd
|
|
|
548
914
|
});
|
|
549
915
|
logger.verbose(`Accept ownership of fee asset in ${acceptTokenOwnershipTxHash}`);
|
|
550
916
|
txHashes.push(acceptTokenOwnershipTxHash);
|
|
917
|
+
} else if (useExternalToken) {
|
|
918
|
+
logger.verbose('Skipping fee asset ownership transfer due to external token usage');
|
|
551
919
|
}
|
|
920
|
+
// Either deploy or at least predict the address of the date gated relayer
|
|
921
|
+
const dateGatedRelayer = await deployer.deploy(DateGatedRelayerArtifact, [
|
|
922
|
+
governanceAddress.toString(),
|
|
923
|
+
1798761600n
|
|
924
|
+
]);
|
|
552
925
|
// If the owner is not the Governance contract, transfer ownership to the Governance contract
|
|
553
|
-
if (acceleratedTestDeployments || await coinIssuerContract.read.owner()
|
|
926
|
+
if (acceleratedTestDeployments || await coinIssuerContract.read.owner() === deployer.client.account.address) {
|
|
554
927
|
const { txHash: transferOwnershipTxHash } = await deployer.sendTransaction({
|
|
555
928
|
to: coinIssuerContract.address,
|
|
556
929
|
data: encodeFunctionData({
|
|
557
930
|
abi: CoinIssuerArtifact.contractAbi,
|
|
558
931
|
functionName: 'transferOwnership',
|
|
559
932
|
args: [
|
|
560
|
-
getAddress(
|
|
933
|
+
getAddress(dateGatedRelayer.address.toString())
|
|
561
934
|
]
|
|
562
935
|
})
|
|
563
936
|
});
|
|
564
|
-
logger.verbose(`Transferring the ownership of the coin issuer contract at ${coinIssuerAddress} to the
|
|
937
|
+
logger.verbose(`Transferring the ownership of the coin issuer contract at ${coinIssuerAddress} to the DateGatedRelayer ${dateGatedRelayer.address} in tx ${transferOwnershipTxHash}`);
|
|
565
938
|
txHashes.push(transferOwnershipTxHash);
|
|
566
939
|
}
|
|
567
940
|
// Wait for all actions to be mined
|
|
@@ -569,6 +942,9 @@ export const handoverToGovernance = async (extendedClient, deployer, registryAdd
|
|
|
569
942
|
await Promise.all(txHashes.map((txHash)=>extendedClient.waitForTransactionReceipt({
|
|
570
943
|
hash: txHash
|
|
571
944
|
})));
|
|
945
|
+
return {
|
|
946
|
+
dateGatedRelayerAddress: dateGatedRelayer.address
|
|
947
|
+
};
|
|
572
948
|
};
|
|
573
949
|
/*
|
|
574
950
|
* Adds multiple validators to the rollup
|
|
@@ -596,85 +972,94 @@ export const handoverToGovernance = async (extendedClient, deployer, registryAdd
|
|
|
596
972
|
}
|
|
597
973
|
validators = enrichedValidators.filter((v)=>v.status === 0).map((v)=>v.operator);
|
|
598
974
|
}
|
|
599
|
-
if (validators.length
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
975
|
+
if (validators.length === 0) {
|
|
976
|
+
logger.warn('No validators to add. Skipping.');
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
const gseContract = new GSEContract(extendedClient, gseAddress);
|
|
980
|
+
const multiAdder = (await deployer.deploy(MultiAdderArtifact, [
|
|
981
|
+
rollupAddress,
|
|
982
|
+
deployer.client.account.address
|
|
983
|
+
])).address;
|
|
984
|
+
const makeValidatorTuples = async (validator)=>{
|
|
985
|
+
const registrationTuple = await gseContract.makeRegistrationTuple(validator.bn254SecretKey.getValue());
|
|
986
|
+
return {
|
|
987
|
+
attester: getAddress(validator.attester.toString()),
|
|
988
|
+
withdrawer: getAddress(validator.withdrawer.toString()),
|
|
989
|
+
...registrationTuple
|
|
612
990
|
};
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
991
|
+
};
|
|
992
|
+
const validatorsTuples = await Promise.all(validators.map(makeValidatorTuples));
|
|
993
|
+
// Mint tokens, approve them, use cheat code to initialize validator set without setting up the epoch.
|
|
994
|
+
const stakeNeeded = activationThreshold * BigInt(validators.length);
|
|
995
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction({
|
|
996
|
+
to: stakingAssetAddress,
|
|
997
|
+
data: encodeFunctionData({
|
|
998
|
+
abi: StakingAssetArtifact.contractAbi,
|
|
999
|
+
functionName: 'mint',
|
|
1000
|
+
args: [
|
|
1001
|
+
multiAdder.toString(),
|
|
1002
|
+
stakeNeeded
|
|
1003
|
+
]
|
|
1004
|
+
})
|
|
1005
|
+
});
|
|
1006
|
+
const entryQueueLengthBefore = await rollup.getEntryQueueLength();
|
|
1007
|
+
const validatorCountBefore = await rollup.getActiveAttesterCount();
|
|
1008
|
+
logger.info(`Adding ${validators.length} validators to the rollup`);
|
|
1009
|
+
const chunkSize = 16;
|
|
1010
|
+
// We will add `chunkSize` validators to the queue until we have covered all of our validators.
|
|
1011
|
+
// The `chunkSize` needs to be small enough to fit inside a single tx, therefore 16.
|
|
1012
|
+
for (const c of chunk(validatorsTuples, chunkSize)){
|
|
616
1013
|
await deployer.l1TxUtils.sendAndMonitorTransaction({
|
|
617
|
-
to:
|
|
1014
|
+
to: multiAdder.toString(),
|
|
618
1015
|
data: encodeFunctionData({
|
|
619
|
-
abi:
|
|
620
|
-
functionName: '
|
|
1016
|
+
abi: MultiAdderArtifact.contractAbi,
|
|
1017
|
+
functionName: 'addValidators',
|
|
621
1018
|
args: [
|
|
622
|
-
|
|
623
|
-
|
|
1019
|
+
c,
|
|
1020
|
+
BigInt(0)
|
|
624
1021
|
]
|
|
625
1022
|
})
|
|
1023
|
+
}, {
|
|
1024
|
+
gasLimit: 16_000_000n
|
|
626
1025
|
});
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
validatorsTuples,
|
|
640
|
-
true
|
|
641
|
-
]
|
|
642
|
-
})
|
|
643
|
-
}, {
|
|
644
|
-
gasLimit: 40_000_000n
|
|
645
|
-
});
|
|
646
|
-
await deployer.l1TxUtils.sendAndMonitorTransaction({
|
|
647
|
-
to: rollupAddress,
|
|
648
|
-
data: encodeFunctionData({
|
|
649
|
-
abi: RollupArtifact.contractAbi,
|
|
650
|
-
functionName: 'flushEntryQueue',
|
|
651
|
-
args: []
|
|
652
|
-
})
|
|
653
|
-
}, {
|
|
654
|
-
gasLimit: 40_000_000n
|
|
655
|
-
});
|
|
656
|
-
} else {
|
|
657
|
-
await deployer.l1TxUtils.sendAndMonitorTransaction({
|
|
658
|
-
to: multiAdder.toString(),
|
|
659
|
-
data: encodeFunctionData({
|
|
660
|
-
abi: MultiAdderArtifact.contractAbi,
|
|
661
|
-
functionName: 'addValidators',
|
|
662
|
-
args: [
|
|
663
|
-
validatorsTuples,
|
|
664
|
-
false
|
|
665
|
-
]
|
|
666
|
-
})
|
|
667
|
-
}, {
|
|
668
|
-
gasLimit: 45_000_000n
|
|
669
|
-
});
|
|
1026
|
+
}
|
|
1027
|
+
// After adding to the queue, we will now try to flush from it.
|
|
1028
|
+
// We are explicitly doing this as a second step instead of as part of adding to benefit
|
|
1029
|
+
// from the accounting used to speed the process up.
|
|
1030
|
+
// As the queue computes the amount of possible flushes in an epoch when told to flush,
|
|
1031
|
+
// waiting until we have added all we want allows us to benefit in the case were we added
|
|
1032
|
+
// enough to pass the bootstrap set size without needing to wait another epoch.
|
|
1033
|
+
// This is useful when we are testing as it speeds up the tests slightly.
|
|
1034
|
+
while(true){
|
|
1035
|
+
// If the queue is empty, we can break
|
|
1036
|
+
if (await rollup.getEntryQueueLength() == 0n) {
|
|
1037
|
+
break;
|
|
670
1038
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
throw new Error(`Failed to add ${validators.length} validators. Active validators: ${validatorCountBefore} -> ${validatorCountAfter}. Queue: ${entryQueueLengthBefore} -> ${entryQueueLengthAfter}`);
|
|
1039
|
+
// If there are no available validator flushes, no need to even try
|
|
1040
|
+
if (await rollup.getAvailableValidatorFlushes() == 0n) {
|
|
1041
|
+
break;
|
|
675
1042
|
}
|
|
676
|
-
|
|
1043
|
+
// Note that we are flushing at most `chunkSize` at each call
|
|
1044
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction({
|
|
1045
|
+
to: rollup.address,
|
|
1046
|
+
data: encodeFunctionData({
|
|
1047
|
+
abi: RollupArtifact.contractAbi,
|
|
1048
|
+
functionName: 'flushEntryQueue',
|
|
1049
|
+
args: [
|
|
1050
|
+
BigInt(chunkSize)
|
|
1051
|
+
]
|
|
1052
|
+
})
|
|
1053
|
+
}, {
|
|
1054
|
+
gasLimit: 16_000_000n
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
const entryQueueLengthAfter = await rollup.getEntryQueueLength();
|
|
1058
|
+
const validatorCountAfter = await rollup.getActiveAttesterCount();
|
|
1059
|
+
if (entryQueueLengthAfter + validatorCountAfter < entryQueueLengthBefore + validatorCountBefore + BigInt(validators.length)) {
|
|
1060
|
+
throw new Error(`Failed to add ${validators.length} validators. Active validators: ${validatorCountBefore} -> ${validatorCountAfter}. Queue: ${entryQueueLengthBefore} -> ${entryQueueLengthAfter}. A likely issue is the bootstrap size.`);
|
|
677
1061
|
}
|
|
1062
|
+
logger.info(`Added ${validators.length} validators. Active validators: ${validatorCountBefore} -> ${validatorCountAfter}. Queue: ${entryQueueLengthBefore} -> ${entryQueueLengthAfter}`);
|
|
678
1063
|
}
|
|
679
1064
|
};
|
|
680
1065
|
/**
|
|
@@ -687,11 +1072,11 @@ export const handoverToGovernance = async (extendedClient, deployer, registryAdd
|
|
|
687
1072
|
* @param logger - The logger.
|
|
688
1073
|
*/ // eslint-disable-next-line camelcase
|
|
689
1074
|
export const cheat_initializeFeeAssetHandler = async (extendedClient, deployer, feeAssetAddress, logger)=>{
|
|
690
|
-
const feeAssetHandlerAddress = await deployer.deploy(FeeAssetHandlerArtifact, [
|
|
1075
|
+
const feeAssetHandlerAddress = (await deployer.deploy(FeeAssetHandlerArtifact, [
|
|
691
1076
|
extendedClient.account.address,
|
|
692
1077
|
feeAssetAddress.toString(),
|
|
693
1078
|
BigInt(1e18)
|
|
694
|
-
]);
|
|
1079
|
+
])).address;
|
|
695
1080
|
logger.verbose(`Deployed FeeAssetHandler at ${feeAssetHandlerAddress}`);
|
|
696
1081
|
const { txHash } = await deployer.sendTransaction({
|
|
697
1082
|
to: feeAssetAddress.toString(),
|
|
@@ -720,6 +1105,9 @@ export const cheat_initializeFeeAssetHandler = async (extendedClient, deployer,
|
|
|
720
1105
|
*/ export const deployL1Contracts = async (rpcUrls, account, chain, logger, args, txUtilsConfig = getL1TxUtilsConfigEnvVars(), createVerificationJson = false)=>{
|
|
721
1106
|
logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`);
|
|
722
1107
|
validateConfig(args);
|
|
1108
|
+
if (args.initialValidators && args.initialValidators.length > 0 && args.existingTokenAddress) {
|
|
1109
|
+
throw new Error('Cannot deploy with both initialValidators and existingTokenAddress. ' + 'Initial validator funding requires minting tokens, which is not possible with an external token.');
|
|
1110
|
+
}
|
|
723
1111
|
const l1Client = createExtendedL1Client(rpcUrls, account, chain);
|
|
724
1112
|
// Deploy multicall3 if it does not exist in this network
|
|
725
1113
|
await deployMulticall3(l1Client, logger);
|
|
@@ -757,205 +1145,15 @@ export const cheat_initializeFeeAssetHandler = async (extendedClient, deployer,
|
|
|
757
1145
|
logger.verbose('Waiting for rollup and slash factory to be deployed');
|
|
758
1146
|
await deployer.waitForDeployments();
|
|
759
1147
|
// Now that the rollup has been deployed and added to the registry, transfer ownership to governance
|
|
760
|
-
await handoverToGovernance(l1Client, deployer, registryAddress, gseAddress, coinIssuerAddress, feeAssetAddress, governanceAddress, logger, args.acceleratedTestDeployments);
|
|
1148
|
+
const { dateGatedRelayerAddress } = await handoverToGovernance(l1Client, deployer, registryAddress, gseAddress, coinIssuerAddress, feeAssetAddress, governanceAddress, logger, args.acceleratedTestDeployments, !!args.existingTokenAddress);
|
|
761
1149
|
logger.info(`Handing over to governance complete`);
|
|
762
1150
|
logger.verbose(`All transactions for L1 deployment have been mined`);
|
|
763
1151
|
const l1Contracts = await RegistryContract.collectAddresses(l1Client, registryAddress, 'canonical');
|
|
764
1152
|
logger.info(`Aztec L1 contracts initialized`, l1Contracts);
|
|
765
1153
|
// Write verification data (constructor args + linked libraries) to file for later forge verify
|
|
766
1154
|
if (createVerificationJson) {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
const rollupAddr = l1Contracts.rollupAddress.toString();
|
|
770
|
-
const inboxAddr = l1Contracts.inboxAddress.toString();
|
|
771
|
-
const outboxAddr = l1Contracts.outboxAddress.toString();
|
|
772
|
-
const feeAsset = l1Contracts.feeJuiceAddress.toString();
|
|
773
|
-
const version = await rollup.getVersion();
|
|
774
|
-
const inboxCtor = encodeAbiParameters([
|
|
775
|
-
{
|
|
776
|
-
type: 'address'
|
|
777
|
-
},
|
|
778
|
-
{
|
|
779
|
-
type: 'address'
|
|
780
|
-
},
|
|
781
|
-
{
|
|
782
|
-
type: 'uint256'
|
|
783
|
-
},
|
|
784
|
-
{
|
|
785
|
-
type: 'uint256'
|
|
786
|
-
}
|
|
787
|
-
], [
|
|
788
|
-
rollupAddr,
|
|
789
|
-
feeAsset,
|
|
790
|
-
version,
|
|
791
|
-
BigInt(L1_TO_L2_MSG_SUBTREE_HEIGHT)
|
|
792
|
-
]);
|
|
793
|
-
const outboxCtor = encodeAbiParameters([
|
|
794
|
-
{
|
|
795
|
-
type: 'address'
|
|
796
|
-
},
|
|
797
|
-
{
|
|
798
|
-
type: 'uint256'
|
|
799
|
-
}
|
|
800
|
-
], [
|
|
801
|
-
rollupAddr,
|
|
802
|
-
version
|
|
803
|
-
]);
|
|
804
|
-
deployer.verificationRecords.push({
|
|
805
|
-
name: 'Inbox',
|
|
806
|
-
address: inboxAddr,
|
|
807
|
-
constructorArgsHex: inboxCtor,
|
|
808
|
-
libraries: []
|
|
809
|
-
}, {
|
|
810
|
-
name: 'Outbox',
|
|
811
|
-
address: outboxAddr,
|
|
812
|
-
constructorArgsHex: outboxCtor,
|
|
813
|
-
libraries: []
|
|
814
|
-
});
|
|
815
|
-
// Include Slasher and SlashingProposer (if deployed) in verification data
|
|
816
|
-
try {
|
|
817
|
-
const slasherAddrHex = await rollup.getSlasher();
|
|
818
|
-
const slasherAddr = EthAddress.fromString(slasherAddrHex);
|
|
819
|
-
if (!slasherAddr.isZero()) {
|
|
820
|
-
// Slasher constructor: (address _vetoer, address _governance)
|
|
821
|
-
const slasherCtor = encodeAbiParameters([
|
|
822
|
-
{
|
|
823
|
-
type: 'address'
|
|
824
|
-
},
|
|
825
|
-
{
|
|
826
|
-
type: 'address'
|
|
827
|
-
}
|
|
828
|
-
], [
|
|
829
|
-
args.slashingVetoer.toString(),
|
|
830
|
-
l1Client.account.address
|
|
831
|
-
]);
|
|
832
|
-
deployer.verificationRecords.push({
|
|
833
|
-
name: 'Slasher',
|
|
834
|
-
address: slasherAddr.toString(),
|
|
835
|
-
constructorArgsHex: slasherCtor,
|
|
836
|
-
libraries: []
|
|
837
|
-
});
|
|
838
|
-
// Proposer address is stored in Slasher.PROPOSER()
|
|
839
|
-
const proposerAddr = (await rollup.getSlashingProposerAddress()).toString();
|
|
840
|
-
// Compute constructor args matching deployment path in RollupCore
|
|
841
|
-
const computedRoundSize = BigInt(args.slashingRoundSizeInEpochs * args.aztecEpochDuration);
|
|
842
|
-
const computedQuorum = BigInt(args.slashingQuorum ?? args.slashingRoundSizeInEpochs * args.aztecEpochDuration / 2 + 1);
|
|
843
|
-
const lifetimeInRounds = BigInt(args.slashingLifetimeInRounds);
|
|
844
|
-
const executionDelayInRounds = BigInt(args.slashingExecutionDelayInRounds);
|
|
845
|
-
if (args.slasherFlavor === 'tally') {
|
|
846
|
-
const slashAmounts = [
|
|
847
|
-
args.slashAmountSmall,
|
|
848
|
-
args.slashAmountMedium,
|
|
849
|
-
args.slashAmountLarge
|
|
850
|
-
];
|
|
851
|
-
const committeeSize = BigInt(args.aztecTargetCommitteeSize);
|
|
852
|
-
const epochDuration = BigInt(args.aztecEpochDuration);
|
|
853
|
-
const slashOffsetInRounds = BigInt(args.slashingOffsetInRounds);
|
|
854
|
-
const proposerCtor = encodeAbiParameters([
|
|
855
|
-
{
|
|
856
|
-
type: 'address'
|
|
857
|
-
},
|
|
858
|
-
{
|
|
859
|
-
type: 'address'
|
|
860
|
-
},
|
|
861
|
-
{
|
|
862
|
-
type: 'uint256'
|
|
863
|
-
},
|
|
864
|
-
{
|
|
865
|
-
type: 'uint256'
|
|
866
|
-
},
|
|
867
|
-
{
|
|
868
|
-
type: 'uint256'
|
|
869
|
-
},
|
|
870
|
-
{
|
|
871
|
-
type: 'uint256'
|
|
872
|
-
},
|
|
873
|
-
{
|
|
874
|
-
type: 'uint256[3]'
|
|
875
|
-
},
|
|
876
|
-
{
|
|
877
|
-
type: 'uint256'
|
|
878
|
-
},
|
|
879
|
-
{
|
|
880
|
-
type: 'uint256'
|
|
881
|
-
},
|
|
882
|
-
{
|
|
883
|
-
type: 'uint256'
|
|
884
|
-
}
|
|
885
|
-
], [
|
|
886
|
-
rollup.address,
|
|
887
|
-
slasherAddr.toString(),
|
|
888
|
-
computedQuorum,
|
|
889
|
-
computedRoundSize,
|
|
890
|
-
lifetimeInRounds,
|
|
891
|
-
executionDelayInRounds,
|
|
892
|
-
slashAmounts,
|
|
893
|
-
committeeSize,
|
|
894
|
-
epochDuration,
|
|
895
|
-
slashOffsetInRounds
|
|
896
|
-
]);
|
|
897
|
-
deployer.verificationRecords.push({
|
|
898
|
-
name: 'TallySlashingProposer',
|
|
899
|
-
address: proposerAddr,
|
|
900
|
-
constructorArgsHex: proposerCtor,
|
|
901
|
-
libraries: []
|
|
902
|
-
});
|
|
903
|
-
} else if (args.slasherFlavor === 'empire') {
|
|
904
|
-
const proposerCtor = encodeAbiParameters([
|
|
905
|
-
{
|
|
906
|
-
type: 'address'
|
|
907
|
-
},
|
|
908
|
-
{
|
|
909
|
-
type: 'address'
|
|
910
|
-
},
|
|
911
|
-
{
|
|
912
|
-
type: 'uint256'
|
|
913
|
-
},
|
|
914
|
-
{
|
|
915
|
-
type: 'uint256'
|
|
916
|
-
},
|
|
917
|
-
{
|
|
918
|
-
type: 'uint256'
|
|
919
|
-
},
|
|
920
|
-
{
|
|
921
|
-
type: 'uint256'
|
|
922
|
-
}
|
|
923
|
-
], [
|
|
924
|
-
rollup.address,
|
|
925
|
-
slasherAddr.toString(),
|
|
926
|
-
computedQuorum,
|
|
927
|
-
computedRoundSize,
|
|
928
|
-
lifetimeInRounds,
|
|
929
|
-
executionDelayInRounds
|
|
930
|
-
]);
|
|
931
|
-
deployer.verificationRecords.push({
|
|
932
|
-
name: 'EmpireSlashingProposer',
|
|
933
|
-
address: proposerAddr,
|
|
934
|
-
constructorArgsHex: proposerCtor,
|
|
935
|
-
libraries: []
|
|
936
|
-
});
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
} catch (e) {
|
|
940
|
-
logger.warn(`Failed to add Slasher/Proposer verification records: ${String(e)}`);
|
|
941
|
-
}
|
|
942
|
-
const date = new Date();
|
|
943
|
-
const formattedDate = date.toISOString().slice(2, 19).replace(/[-T:]/g, '');
|
|
944
|
-
// Ensure the verification output directory exists
|
|
945
|
-
await mkdir(createVerificationJson, {
|
|
946
|
-
recursive: true
|
|
947
|
-
});
|
|
948
|
-
const verificationOutputPath = `${createVerificationJson}/l1-verify-${chain.id}-${formattedDate.slice(0, 6)}-${formattedDate.slice(6)}.json`;
|
|
949
|
-
const verificationData = {
|
|
950
|
-
chainId: chain.id,
|
|
951
|
-
network: networkName,
|
|
952
|
-
records: deployer.verificationRecords
|
|
953
|
-
};
|
|
954
|
-
await writeFile(verificationOutputPath, JSON.stringify(verificationData, null, 2));
|
|
955
|
-
logger.info(`Wrote L1 verification data to ${verificationOutputPath}`);
|
|
956
|
-
} catch (e) {
|
|
957
|
-
logger.warn(`Failed to write L1 verification data file: ${String(e)}`);
|
|
958
|
-
}
|
|
1155
|
+
await generateRollupVerificationRecords(rollup, deployer, args, l1Contracts, l1Client, logger);
|
|
1156
|
+
await writeVerificationJson(deployer, createVerificationJson, chain.id, '', logger);
|
|
959
1157
|
}
|
|
960
1158
|
if (isAnvilTestChain(chain.id)) {
|
|
961
1159
|
// @note We make a time jump PAST the very first slot to not have to deal with the edge case of the first slot.
|
|
@@ -963,8 +1161,8 @@ export const cheat_initializeFeeAssetHandler = async (extendedClient, deployer,
|
|
|
963
1161
|
try {
|
|
964
1162
|
// Need to get the time
|
|
965
1163
|
const currentSlot = await rollup.getSlotNumber();
|
|
966
|
-
if (
|
|
967
|
-
const ts = Number(await rollup.getTimestampForSlot(
|
|
1164
|
+
if (currentSlot === 0) {
|
|
1165
|
+
const ts = Number(await rollup.getTimestampForSlot(SlotNumber(1)));
|
|
968
1166
|
await rpcCall('evm_setNextBlockTimestamp', [
|
|
969
1167
|
ts
|
|
970
1168
|
]);
|
|
@@ -972,7 +1170,7 @@ export const cheat_initializeFeeAssetHandler = async (extendedClient, deployer,
|
|
|
972
1170
|
1
|
|
973
1171
|
]);
|
|
974
1172
|
const currentSlot = await rollup.getSlotNumber();
|
|
975
|
-
if (
|
|
1173
|
+
if (currentSlot !== 1) {
|
|
976
1174
|
throw new Error(`Error jumping time: current slot is ${currentSlot}`);
|
|
977
1175
|
}
|
|
978
1176
|
logger.info(`Jumped to slot 1`);
|
|
@@ -990,7 +1188,8 @@ export const cheat_initializeFeeAssetHandler = async (extendedClient, deployer,
|
|
|
990
1188
|
feeAssetHandlerAddress,
|
|
991
1189
|
stakingAssetHandlerAddress,
|
|
992
1190
|
zkPassportVerifierAddress,
|
|
993
|
-
coinIssuerAddress
|
|
1191
|
+
coinIssuerAddress,
|
|
1192
|
+
dateGatedRelayerAddress
|
|
994
1193
|
}
|
|
995
1194
|
};
|
|
996
1195
|
};
|
|
@@ -1015,20 +1214,27 @@ export class L1Deployer {
|
|
|
1015
1214
|
this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), {
|
|
1016
1215
|
size: 32
|
|
1017
1216
|
}) : undefined;
|
|
1018
|
-
this.l1TxUtils = createL1TxUtilsFromViemWallet(this.client,
|
|
1217
|
+
this.l1TxUtils = createL1TxUtilsFromViemWallet(this.client, {
|
|
1218
|
+
logger: this.logger,
|
|
1219
|
+
dateProvider
|
|
1220
|
+
}, {
|
|
1221
|
+
...this.txUtilsConfig,
|
|
1222
|
+
debugMaxGasLimit: acceleratedTestDeployments
|
|
1223
|
+
});
|
|
1019
1224
|
}
|
|
1020
1225
|
async deploy(params, args, opts = {}) {
|
|
1021
1226
|
this.logger.debug(`Deploying ${params.name} contract`, {
|
|
1022
1227
|
args
|
|
1023
1228
|
});
|
|
1024
1229
|
try {
|
|
1025
|
-
const { txHash, address, deployedLibraries } = await deployL1Contract(this.client, params.contractAbi, params.contractBytecode, args ?? [], {
|
|
1230
|
+
const { txHash, address, deployedLibraries, existed } = await deployL1Contract(this.client, params.contractAbi, params.contractBytecode, args ?? [], {
|
|
1026
1231
|
salt: this.salt,
|
|
1027
1232
|
libraries: params.libraries,
|
|
1028
1233
|
logger: this.logger,
|
|
1029
1234
|
l1TxUtils: this.l1TxUtils,
|
|
1030
1235
|
acceleratedTestDeployments: this.acceleratedTestDeployments,
|
|
1031
|
-
gasLimit: opts.gasLimit
|
|
1236
|
+
gasLimit: opts.gasLimit,
|
|
1237
|
+
noSimulation: opts.noSimulation
|
|
1032
1238
|
});
|
|
1033
1239
|
if (txHash) {
|
|
1034
1240
|
this.txHashes.push(txHash);
|
|
@@ -1053,7 +1259,10 @@ export class L1Deployer {
|
|
|
1053
1259
|
libraries: deployedLibraries ?? []
|
|
1054
1260
|
});
|
|
1055
1261
|
}
|
|
1056
|
-
return
|
|
1262
|
+
return {
|
|
1263
|
+
address,
|
|
1264
|
+
existed
|
|
1265
|
+
};
|
|
1057
1266
|
} catch (error) {
|
|
1058
1267
|
throw new Error(`Failed to deploy ${params.name}`, {
|
|
1059
1268
|
cause: formatViemError(error)
|
|
@@ -1083,10 +1292,13 @@ export class L1Deployer {
|
|
|
1083
1292
|
});
|
|
1084
1293
|
}
|
|
1085
1294
|
sendTransaction(tx, options) {
|
|
1086
|
-
return this.l1TxUtils.sendTransaction(tx, options)
|
|
1295
|
+
return this.l1TxUtils.sendTransaction(tx, options).then(({ txHash, state })=>({
|
|
1296
|
+
txHash,
|
|
1297
|
+
gasLimit: state.gasLimit,
|
|
1298
|
+
gasPrice: state.gasPrice
|
|
1299
|
+
}));
|
|
1087
1300
|
}
|
|
1088
1301
|
}
|
|
1089
|
-
// docs:start:deployL1Contract
|
|
1090
1302
|
/**
|
|
1091
1303
|
* Helper function to deploy ETH contracts.
|
|
1092
1304
|
* @param walletClient - A viem WalletClient.
|
|
@@ -1100,11 +1312,16 @@ export class L1Deployer {
|
|
|
1100
1312
|
let txHash = undefined;
|
|
1101
1313
|
let resultingAddress = undefined;
|
|
1102
1314
|
const deployedLibraries = [];
|
|
1103
|
-
const { salt: saltFromOpts, libraries, logger, gasLimit, acceleratedTestDeployments } = opts;
|
|
1315
|
+
const { salt: saltFromOpts, libraries, logger, gasLimit, acceleratedTestDeployments, noSimulation } = opts;
|
|
1104
1316
|
let { l1TxUtils } = opts;
|
|
1105
1317
|
if (!l1TxUtils) {
|
|
1106
1318
|
const config = getL1TxUtilsConfigEnvVars();
|
|
1107
|
-
l1TxUtils = createL1TxUtilsFromViemWallet(extendedClient,
|
|
1319
|
+
l1TxUtils = createL1TxUtilsFromViemWallet(extendedClient, {
|
|
1320
|
+
logger
|
|
1321
|
+
}, {
|
|
1322
|
+
...config,
|
|
1323
|
+
debugMaxGasLimit: acceleratedTestDeployments
|
|
1324
|
+
});
|
|
1108
1325
|
}
|
|
1109
1326
|
if (libraries) {
|
|
1110
1327
|
// Note that this does NOT work well for linked libraries having linked libraries.
|
|
@@ -1179,6 +1396,7 @@ export class L1Deployer {
|
|
|
1179
1396
|
logger?.verbose(`Skipping waiting for linked libraries to be deployed ${acceleratedTestDeployments ? '(accelerated test deployments)' : ''}`);
|
|
1180
1397
|
}
|
|
1181
1398
|
}
|
|
1399
|
+
let existed = false;
|
|
1182
1400
|
if (saltFromOpts) {
|
|
1183
1401
|
logger?.info(`Deploying contract with salt ${saltFromOpts}`);
|
|
1184
1402
|
const { address, paddedSalt: salt, calldata } = getExpectedAddress(abi, bytecode, args, saltFromOpts);
|
|
@@ -1187,26 +1405,28 @@ export class L1Deployer {
|
|
|
1187
1405
|
address: resultingAddress
|
|
1188
1406
|
});
|
|
1189
1407
|
if (existing === undefined || existing === '0x') {
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1408
|
+
if (!noSimulation) {
|
|
1409
|
+
try {
|
|
1410
|
+
await l1TxUtils.simulate({
|
|
1411
|
+
to: DEPLOYER_ADDRESS,
|
|
1412
|
+
data: concatHex([
|
|
1413
|
+
salt,
|
|
1414
|
+
calldata
|
|
1415
|
+
]),
|
|
1416
|
+
gas: gasLimit
|
|
1417
|
+
});
|
|
1418
|
+
} catch (err) {
|
|
1419
|
+
logger?.error(`Failed to simulate deployment tx using universal deployer`, err);
|
|
1420
|
+
await l1TxUtils.simulate({
|
|
1421
|
+
to: null,
|
|
1422
|
+
data: encodeDeployData({
|
|
1423
|
+
abi,
|
|
1424
|
+
bytecode,
|
|
1425
|
+
args
|
|
1426
|
+
}),
|
|
1427
|
+
gas: gasLimit
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1210
1430
|
}
|
|
1211
1431
|
const res = await l1TxUtils.sendTransaction({
|
|
1212
1432
|
to: DEPLOYER_ADDRESS,
|
|
@@ -1221,6 +1441,7 @@ export class L1Deployer {
|
|
|
1221
1441
|
logger?.verbose(`Deployed contract with salt ${salt} to address ${resultingAddress} in tx ${txHash}.`);
|
|
1222
1442
|
} else {
|
|
1223
1443
|
logger?.verbose(`Skipping existing deployment of contract with salt ${salt} to address ${resultingAddress}`);
|
|
1444
|
+
existed = true;
|
|
1224
1445
|
}
|
|
1225
1446
|
} else {
|
|
1226
1447
|
const deployData = encodeDeployData({
|
|
@@ -1231,6 +1452,8 @@ export class L1Deployer {
|
|
|
1231
1452
|
const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
|
|
1232
1453
|
to: null,
|
|
1233
1454
|
data: deployData
|
|
1455
|
+
}, {
|
|
1456
|
+
gasLimit
|
|
1234
1457
|
});
|
|
1235
1458
|
txHash = receipt.transactionHash;
|
|
1236
1459
|
resultingAddress = receipt.contractAddress;
|
|
@@ -1241,7 +1464,8 @@ export class L1Deployer {
|
|
|
1241
1464
|
return {
|
|
1242
1465
|
address: EthAddress.fromString(resultingAddress),
|
|
1243
1466
|
txHash,
|
|
1244
|
-
deployedLibraries
|
|
1467
|
+
deployedLibraries,
|
|
1468
|
+
existed
|
|
1245
1469
|
};
|
|
1246
1470
|
}
|
|
1247
1471
|
export function getExpectedAddress(abi, bytecode, args, salt) {
|
|
@@ -1264,4 +1488,4 @@ export function getExpectedAddress(abi, bytecode, args, salt) {
|
|
|
1264
1488
|
paddedSalt,
|
|
1265
1489
|
calldata
|
|
1266
1490
|
};
|
|
1267
|
-
}
|
|
1491
|
+
}
|