@aztec/ethereum 2.0.0-nightly.20250902 → 3.0.0-nightly.20250904
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/config.d.ts.map +1 -1
- package/dest/config.js +61 -54
- package/dest/contracts/fee_asset_handler.d.ts +3 -2
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.js +14 -0
- package/dest/contracts/fee_juice.d.ts +2 -1
- package/dest/contracts/fee_juice.d.ts.map +1 -1
- package/dest/contracts/fee_juice.js +6 -0
- package/dest/contracts/governance.d.ts +1 -1
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +3 -0
- package/dest/contracts/governance_proposer.d.ts +1 -1
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +3 -0
- package/dest/contracts/gse.d.ts +2 -0
- package/dest/contracts/gse.d.ts.map +1 -1
- package/dest/contracts/gse.js +6 -0
- package/dest/deploy_l1_contracts.d.ts +18 -4
- package/dest/deploy_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_l1_contracts.js +383 -61
- package/dest/l1_artifacts.d.ts +39210 -39196
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.d.ts +3 -2
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +11 -0
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +2 -1
- package/dest/test/tx_delayer.d.ts +2 -2
- package/dest/test/tx_delayer.d.ts.map +1 -1
- package/dest/test/tx_delayer.js +4 -4
- package/package.json +5 -4
- package/src/config.ts +81 -72
- package/src/contracts/fee_asset_handler.ts +17 -2
- package/src/contracts/fee_juice.ts +8 -1
- package/src/contracts/governance.ts +4 -1
- package/src/contracts/governance_proposer.ts +4 -1
- package/src/contracts/gse.ts +8 -0
- package/src/deploy_l1_contracts.ts +357 -52
- package/src/test/eth_cheat_codes.ts +12 -2
- package/src/test/rollup_cheat_codes.ts +5 -1
- package/src/test/tx_delayer.ts +14 -4
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/constants';
|
|
1
2
|
import { SecretValue, getActiveNetworkName } from '@aztec/foundation/config';
|
|
2
3
|
import { keccak256String } from '@aztec/foundation/crypto';
|
|
3
4
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
@@ -8,6 +9,7 @@ import { DateProvider } from '@aztec/foundation/timer';
|
|
|
8
9
|
import type { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
9
10
|
|
|
10
11
|
import type { Abi, Narrow } from 'abitype';
|
|
12
|
+
import { mkdir, writeFile } from 'fs/promises';
|
|
11
13
|
import {
|
|
12
14
|
type Chain,
|
|
13
15
|
type ContractConstructorArgs,
|
|
@@ -15,6 +17,7 @@ import {
|
|
|
15
17
|
type Hex,
|
|
16
18
|
type PrivateKeyAccount,
|
|
17
19
|
concatHex,
|
|
20
|
+
encodeAbiParameters,
|
|
18
21
|
encodeDeployData,
|
|
19
22
|
encodeFunctionData,
|
|
20
23
|
getAddress,
|
|
@@ -129,6 +132,19 @@ export interface ContractArtifacts<TAbi extends Abi | readonly unknown[] = Abi>
|
|
|
129
132
|
libraries?: Libraries;
|
|
130
133
|
}
|
|
131
134
|
|
|
135
|
+
export type VerificationLibraryEntry = {
|
|
136
|
+
file: string;
|
|
137
|
+
contract: string;
|
|
138
|
+
address: string;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export type VerificationRecord = {
|
|
142
|
+
name: string;
|
|
143
|
+
address: string;
|
|
144
|
+
constructorArgsHex: Hex;
|
|
145
|
+
libraries: VerificationLibraryEntry[];
|
|
146
|
+
};
|
|
147
|
+
|
|
132
148
|
export interface DeployL1ContractsArgs extends Omit<L1ContractsConfig, keyof L1TxUtilsConfig> {
|
|
133
149
|
/** The vk tree root. */
|
|
134
150
|
vkTreeRoot: Fr;
|
|
@@ -247,36 +263,14 @@ export const deploySharedContracts = async (
|
|
|
247
263
|
|
|
248
264
|
const coinIssuerAddress = await deployer.deploy(CoinIssuerArtifact, [
|
|
249
265
|
feeAssetAddress.toString(),
|
|
250
|
-
|
|
251
|
-
|
|
266
|
+
1_000_000n * 10n ** 18n, // @todo #8084
|
|
267
|
+
l1Client.account.address,
|
|
252
268
|
]);
|
|
253
269
|
logger.verbose(`Deployed CoinIssuer at ${coinIssuerAddress}`);
|
|
254
270
|
|
|
255
|
-
const feeAsset = getContract({
|
|
256
|
-
address: feeAssetAddress.toString(),
|
|
257
|
-
abi: FeeAssetArtifact.contractAbi,
|
|
258
|
-
client: l1Client,
|
|
259
|
-
});
|
|
260
|
-
|
|
261
271
|
logger.verbose(`Waiting for deployments to complete`);
|
|
262
272
|
await deployer.waitForDeployments();
|
|
263
273
|
|
|
264
|
-
if (args.acceleratedTestDeployments || !(await feeAsset.read.minters([coinIssuerAddress.toString()]))) {
|
|
265
|
-
const { txHash } = await deployer.sendTransaction(
|
|
266
|
-
{
|
|
267
|
-
to: feeAssetAddress.toString(),
|
|
268
|
-
data: encodeFunctionData({
|
|
269
|
-
abi: FeeAssetArtifact.contractAbi,
|
|
270
|
-
functionName: 'addMinter',
|
|
271
|
-
args: [coinIssuerAddress.toString()],
|
|
272
|
-
}),
|
|
273
|
-
},
|
|
274
|
-
{ gasLimit: 100_000n },
|
|
275
|
-
);
|
|
276
|
-
logger.verbose(`Added coin issuer ${coinIssuerAddress} as minter on fee asset in ${txHash}`);
|
|
277
|
-
txHashes.push(txHash);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
274
|
// Registry ownership will be transferred to governance later, after rollup is added
|
|
281
275
|
|
|
282
276
|
let feeAssetHandlerAddress: EthAddress | undefined = undefined;
|
|
@@ -292,20 +286,23 @@ export const deploySharedContracts = async (
|
|
|
292
286
|
feeAssetHandlerAddress = await deployer.deploy(FeeAssetHandlerArtifact, [
|
|
293
287
|
l1Client.account.address,
|
|
294
288
|
feeAssetAddress.toString(),
|
|
295
|
-
BigInt(
|
|
289
|
+
BigInt(1000n * 10n ** 18n),
|
|
296
290
|
]);
|
|
297
291
|
logger.verbose(`Deployed FeeAssetHandler at ${feeAssetHandlerAddress}`);
|
|
298
292
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
293
|
+
// Only if we are "fresh" will we be adding as a minter, otherwise above will simply get same address
|
|
294
|
+
if (needToSetGovernance) {
|
|
295
|
+
const { txHash } = await deployer.sendTransaction({
|
|
296
|
+
to: feeAssetAddress.toString(),
|
|
297
|
+
data: encodeFunctionData({
|
|
298
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
299
|
+
functionName: 'addMinter',
|
|
300
|
+
args: [feeAssetHandlerAddress.toString()],
|
|
301
|
+
}),
|
|
302
|
+
});
|
|
303
|
+
logger.verbose(`Added fee asset handler ${feeAssetHandlerAddress} as minter on fee asset in ${txHash}`);
|
|
304
|
+
txHashes.push(txHash);
|
|
305
|
+
}
|
|
309
306
|
|
|
310
307
|
// Only if on sepolia will we deploy the staking asset handler
|
|
311
308
|
// Should not be deployed to devnet since it would cause caos with sequencers there etc.
|
|
@@ -500,7 +497,12 @@ export const deployRollup = async (
|
|
|
500
497
|
>,
|
|
501
498
|
addresses: Pick<
|
|
502
499
|
L1ContractAddresses,
|
|
503
|
-
|
|
500
|
+
| 'feeJuiceAddress'
|
|
501
|
+
| 'registryAddress'
|
|
502
|
+
| 'rewardDistributorAddress'
|
|
503
|
+
| 'stakingAssetAddress'
|
|
504
|
+
| 'gseAddress'
|
|
505
|
+
| 'governanceAddress'
|
|
504
506
|
>,
|
|
505
507
|
logger: Logger,
|
|
506
508
|
) => {
|
|
@@ -678,6 +680,24 @@ export const deployRollup = async (
|
|
|
678
680
|
);
|
|
679
681
|
}
|
|
680
682
|
|
|
683
|
+
// If the owner is not the Governance contract, transfer ownership to the Governance contract
|
|
684
|
+
logger.verbose(addresses.governanceAddress.toString());
|
|
685
|
+
if (getAddress(await rollupContract.getOwner()) !== getAddress(addresses.governanceAddress.toString())) {
|
|
686
|
+
// TODO(md): add send transaction to the deployer such that we do not need to manage tx hashes here
|
|
687
|
+
const { txHash: transferOwnershipTxHash } = await deployer.sendTransaction({
|
|
688
|
+
to: rollupContract.address,
|
|
689
|
+
data: encodeFunctionData({
|
|
690
|
+
abi: RegistryArtifact.contractAbi,
|
|
691
|
+
functionName: 'transferOwnership',
|
|
692
|
+
args: [getAddress(addresses.governanceAddress.toString())],
|
|
693
|
+
}),
|
|
694
|
+
});
|
|
695
|
+
logger.verbose(
|
|
696
|
+
`Transferring the ownership of the rollup contract at ${rollupContract.address} to the Governance ${addresses.governanceAddress} in tx ${transferOwnershipTxHash}`,
|
|
697
|
+
);
|
|
698
|
+
txHashes.push(transferOwnershipTxHash);
|
|
699
|
+
}
|
|
700
|
+
|
|
681
701
|
await deployer.waitForDeployments();
|
|
682
702
|
await Promise.all(txHashes.map(txHash => extendedClient.waitForTransactionReceipt({ hash: txHash })));
|
|
683
703
|
logger.verbose(`Rollup deployed`);
|
|
@@ -690,6 +710,8 @@ export const handoverToGovernance = async (
|
|
|
690
710
|
deployer: L1Deployer,
|
|
691
711
|
registryAddress: EthAddress,
|
|
692
712
|
gseAddress: EthAddress,
|
|
713
|
+
coinIssuerAddress: EthAddress,
|
|
714
|
+
feeAssetAddress: EthAddress,
|
|
693
715
|
governanceAddress: EthAddress,
|
|
694
716
|
logger: Logger,
|
|
695
717
|
acceleratedTestDeployments: boolean | undefined,
|
|
@@ -707,6 +729,18 @@ export const handoverToGovernance = async (
|
|
|
707
729
|
client: extendedClient,
|
|
708
730
|
});
|
|
709
731
|
|
|
732
|
+
const coinIssuerContract = getContract({
|
|
733
|
+
address: getAddress(coinIssuerAddress.toString()),
|
|
734
|
+
abi: CoinIssuerArtifact.contractAbi,
|
|
735
|
+
client: extendedClient,
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
const feeAsset = getContract({
|
|
739
|
+
address: getAddress(feeAssetAddress.toString()),
|
|
740
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
741
|
+
client: extendedClient,
|
|
742
|
+
});
|
|
743
|
+
|
|
710
744
|
const txHashes: Hex[] = [];
|
|
711
745
|
|
|
712
746
|
// If the owner is not the Governance contract, transfer ownership to the Governance contract
|
|
@@ -746,6 +780,54 @@ export const handoverToGovernance = async (
|
|
|
746
780
|
txHashes.push(transferOwnershipTxHash);
|
|
747
781
|
}
|
|
748
782
|
|
|
783
|
+
if (acceleratedTestDeployments || (await feeAsset.read.owner()) !== coinIssuerAddress.toString()) {
|
|
784
|
+
const { txHash } = await deployer.sendTransaction(
|
|
785
|
+
{
|
|
786
|
+
to: feeAssetAddress.toString(),
|
|
787
|
+
data: encodeFunctionData({
|
|
788
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
789
|
+
functionName: 'transferOwnership',
|
|
790
|
+
args: [coinIssuerAddress.toString()],
|
|
791
|
+
}),
|
|
792
|
+
},
|
|
793
|
+
{ gasLimit: 500_000n },
|
|
794
|
+
);
|
|
795
|
+
logger.verbose(`Transfer ownership of fee asset to coin issuer ${coinIssuerAddress} in ${txHash}`);
|
|
796
|
+
txHashes.push(txHash);
|
|
797
|
+
|
|
798
|
+
const { txHash: acceptTokenOwnershipTxHash } = await deployer.sendTransaction(
|
|
799
|
+
{
|
|
800
|
+
to: coinIssuerAddress.toString(),
|
|
801
|
+
data: encodeFunctionData({
|
|
802
|
+
abi: CoinIssuerArtifact.contractAbi,
|
|
803
|
+
functionName: 'acceptTokenOwnership',
|
|
804
|
+
}),
|
|
805
|
+
},
|
|
806
|
+
{ gasLimit: 500_000n },
|
|
807
|
+
);
|
|
808
|
+
logger.verbose(`Accept ownership of fee asset in ${acceptTokenOwnershipTxHash}`);
|
|
809
|
+
txHashes.push(acceptTokenOwnershipTxHash);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// 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
|
+
) {
|
|
817
|
+
const { txHash: transferOwnershipTxHash } = await deployer.sendTransaction({
|
|
818
|
+
to: coinIssuerContract.address,
|
|
819
|
+
data: encodeFunctionData({
|
|
820
|
+
abi: CoinIssuerArtifact.contractAbi,
|
|
821
|
+
functionName: 'transferOwnership',
|
|
822
|
+
args: [getAddress(governanceAddress.toString())],
|
|
823
|
+
}),
|
|
824
|
+
});
|
|
825
|
+
logger.verbose(
|
|
826
|
+
`Transferring the ownership of the coin issuer contract at ${coinIssuerAddress} to the Governance ${governanceAddress} in tx ${transferOwnershipTxHash}`,
|
|
827
|
+
);
|
|
828
|
+
txHashes.push(transferOwnershipTxHash);
|
|
829
|
+
}
|
|
830
|
+
|
|
749
831
|
// Wait for all actions to be mined
|
|
750
832
|
await deployer.waitForDeployments();
|
|
751
833
|
await Promise.all(txHashes.map(txHash => extendedClient.waitForTransactionReceipt({ hash: txHash })));
|
|
@@ -827,19 +909,51 @@ export const addMultipleValidators = async (
|
|
|
827
909
|
|
|
828
910
|
logger.info(`Adding ${validators.length} validators to the rollup`);
|
|
829
911
|
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
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
|
+
);
|
|
928
|
+
|
|
929
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
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
|
+
}
|
|
843
957
|
|
|
844
958
|
const entryQueueLengthAfter = await rollup.getEntryQueueLength();
|
|
845
959
|
const validatorCountAfter = await rollup.getActiveAttesterCount();
|
|
@@ -914,7 +1028,9 @@ export const deployL1Contracts = async (
|
|
|
914
1028
|
logger: Logger,
|
|
915
1029
|
args: DeployL1ContractsArgs,
|
|
916
1030
|
txUtilsConfig: L1TxUtilsConfig = getL1TxUtilsConfigEnvVars(),
|
|
1031
|
+
createVerificationJson: string | false = false,
|
|
917
1032
|
): Promise<DeployL1ContractsReturnType> => {
|
|
1033
|
+
logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`);
|
|
918
1034
|
validateConfig(args);
|
|
919
1035
|
|
|
920
1036
|
const l1Client = createExtendedL1Client(rpcUrls, account, chain);
|
|
@@ -952,6 +1068,7 @@ export const deployL1Contracts = async (
|
|
|
952
1068
|
args.acceleratedTestDeployments,
|
|
953
1069
|
logger,
|
|
954
1070
|
txUtilsConfig,
|
|
1071
|
+
!!createVerificationJson,
|
|
955
1072
|
);
|
|
956
1073
|
|
|
957
1074
|
const {
|
|
@@ -964,6 +1081,7 @@ export const deployL1Contracts = async (
|
|
|
964
1081
|
governanceAddress,
|
|
965
1082
|
rewardDistributorAddress,
|
|
966
1083
|
zkPassportVerifierAddress,
|
|
1084
|
+
coinIssuerAddress,
|
|
967
1085
|
} = await deploySharedContracts(l1Client, deployer, args, logger);
|
|
968
1086
|
const { rollup, slashFactoryAddress } = await deployRollup(
|
|
969
1087
|
l1Client,
|
|
@@ -975,6 +1093,7 @@ export const deployL1Contracts = async (
|
|
|
975
1093
|
gseAddress,
|
|
976
1094
|
rewardDistributorAddress,
|
|
977
1095
|
stakingAssetAddress,
|
|
1096
|
+
governanceAddress,
|
|
978
1097
|
},
|
|
979
1098
|
logger,
|
|
980
1099
|
);
|
|
@@ -988,6 +1107,8 @@ export const deployL1Contracts = async (
|
|
|
988
1107
|
deployer,
|
|
989
1108
|
registryAddress,
|
|
990
1109
|
gseAddress,
|
|
1110
|
+
coinIssuerAddress,
|
|
1111
|
+
feeAssetAddress,
|
|
991
1112
|
governanceAddress,
|
|
992
1113
|
logger,
|
|
993
1114
|
args.acceleratedTestDeployments,
|
|
@@ -1000,6 +1121,147 @@ export const deployL1Contracts = async (
|
|
|
1000
1121
|
|
|
1001
1122
|
logger.info(`Aztec L1 contracts initialized`, l1Contracts);
|
|
1002
1123
|
|
|
1124
|
+
// Write verification data (constructor args + linked libraries) to file for later forge verify
|
|
1125
|
+
if (createVerificationJson) {
|
|
1126
|
+
try {
|
|
1127
|
+
// Add Inbox / Outbox verification records (constructor args are created inside RollupCore)
|
|
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
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1003
1265
|
if (isAnvilTestChain(chain.id)) {
|
|
1004
1266
|
// @note We make a time jump PAST the very first slot to not have to deal with the edge case of the first slot.
|
|
1005
1267
|
// The edge case being that the genesis block is already occupying slot 0, so we cannot have another block.
|
|
@@ -1032,6 +1294,7 @@ export const deployL1Contracts = async (
|
|
|
1032
1294
|
feeAssetHandlerAddress,
|
|
1033
1295
|
stakingAssetHandlerAddress,
|
|
1034
1296
|
zkPassportVerifierAddress,
|
|
1297
|
+
coinIssuerAddress,
|
|
1035
1298
|
},
|
|
1036
1299
|
};
|
|
1037
1300
|
};
|
|
@@ -1040,6 +1303,7 @@ export class L1Deployer {
|
|
|
1040
1303
|
private salt: Hex | undefined;
|
|
1041
1304
|
private txHashes: Hex[] = [];
|
|
1042
1305
|
public readonly l1TxUtils: L1TxUtils;
|
|
1306
|
+
public readonly verificationRecords: VerificationRecord[] = [];
|
|
1043
1307
|
|
|
1044
1308
|
constructor(
|
|
1045
1309
|
public readonly client: ExtendedViemWalletClient,
|
|
@@ -1048,6 +1312,7 @@ export class L1Deployer {
|
|
|
1048
1312
|
private acceleratedTestDeployments: boolean = false,
|
|
1049
1313
|
private logger: Logger = createLogger('L1Deployer'),
|
|
1050
1314
|
private txUtilsConfig?: L1TxUtilsConfig,
|
|
1315
|
+
private createVerificationJson: boolean = false,
|
|
1051
1316
|
) {
|
|
1052
1317
|
this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), { size: 32 }) : undefined;
|
|
1053
1318
|
this.l1TxUtils = createL1TxUtilsFromViemWallet(
|
|
@@ -1066,7 +1331,7 @@ export class L1Deployer {
|
|
|
1066
1331
|
): Promise<EthAddress> {
|
|
1067
1332
|
this.logger.debug(`Deploying ${params.name} contract`, { args });
|
|
1068
1333
|
try {
|
|
1069
|
-
const { txHash, address } = await deployL1Contract(
|
|
1334
|
+
const { txHash, address, deployedLibraries } = await deployL1Contract(
|
|
1070
1335
|
this.client,
|
|
1071
1336
|
params.contractAbi,
|
|
1072
1337
|
params.contractBytecode,
|
|
@@ -1084,6 +1349,26 @@ export class L1Deployer {
|
|
|
1084
1349
|
this.txHashes.push(txHash);
|
|
1085
1350
|
}
|
|
1086
1351
|
this.logger.debug(`Deployed ${params.name} at ${address}`, { args });
|
|
1352
|
+
|
|
1353
|
+
if (this.createVerificationJson) {
|
|
1354
|
+
// Encode constructor args for verification
|
|
1355
|
+
let constructorArgsHex: Hex = '0x';
|
|
1356
|
+
try {
|
|
1357
|
+
const abiItem: any = (params.contractAbi as any[]).find((x: any) => x && x.type === 'constructor');
|
|
1358
|
+
const inputDefs: any[] = abiItem && Array.isArray(abiItem.inputs) ? abiItem.inputs : [];
|
|
1359
|
+
constructorArgsHex =
|
|
1360
|
+
inputDefs.length > 0 ? (encodeAbiParameters(inputDefs as any, (args ?? []) as any) as Hex) : ('0x' as Hex);
|
|
1361
|
+
} catch {
|
|
1362
|
+
constructorArgsHex = '0x' as Hex;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
this.verificationRecords.push({
|
|
1366
|
+
name: params.name,
|
|
1367
|
+
address: address.toString(),
|
|
1368
|
+
constructorArgsHex,
|
|
1369
|
+
libraries: deployedLibraries ?? [],
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1087
1372
|
return address;
|
|
1088
1373
|
} catch (error) {
|
|
1089
1374
|
throw new Error(`Failed to deploy ${params.name}`, { cause: formatViemError(error) });
|
|
@@ -1142,9 +1427,10 @@ export async function deployL1Contract(
|
|
|
1142
1427
|
gasLimit?: bigint;
|
|
1143
1428
|
acceleratedTestDeployments?: boolean;
|
|
1144
1429
|
} = {},
|
|
1145
|
-
): Promise<{ address: EthAddress; txHash: Hex | undefined }> {
|
|
1430
|
+
): Promise<{ address: EthAddress; txHash: Hex | undefined; deployedLibraries?: VerificationLibraryEntry[] }> {
|
|
1146
1431
|
let txHash: Hex | undefined = undefined;
|
|
1147
1432
|
let resultingAddress: Hex | null | undefined = undefined;
|
|
1433
|
+
const deployedLibraries: VerificationLibraryEntry[] = [];
|
|
1148
1434
|
|
|
1149
1435
|
const { salt: saltFromOpts, libraries, logger, gasLimit, acceleratedTestDeployments } = opts;
|
|
1150
1436
|
let { l1TxUtils } = opts;
|
|
@@ -1179,10 +1465,29 @@ export async function deployL1Contract(
|
|
|
1179
1465
|
optsWithoutLibraries,
|
|
1180
1466
|
);
|
|
1181
1467
|
|
|
1468
|
+
// Log deployed library name and address for easier verification/triage
|
|
1469
|
+
logger?.verbose(`Linked library deployed`, { library: libraryName, address: address.toString(), txHash });
|
|
1470
|
+
|
|
1182
1471
|
if (txHash) {
|
|
1183
1472
|
libraryTxs.push(txHash);
|
|
1184
1473
|
}
|
|
1185
1474
|
|
|
1475
|
+
// Try to find the source file for this library from linkReferences
|
|
1476
|
+
let fileNameForLibrary: string | undefined = undefined;
|
|
1477
|
+
for (const fileName in libraries.linkReferences) {
|
|
1478
|
+
if (libraries.linkReferences[fileName] && libraries.linkReferences[fileName][libraryName]) {
|
|
1479
|
+
fileNameForLibrary = fileName;
|
|
1480
|
+
break;
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
if (fileNameForLibrary) {
|
|
1484
|
+
deployedLibraries.push({
|
|
1485
|
+
file: fileNameForLibrary,
|
|
1486
|
+
contract: libraryName,
|
|
1487
|
+
address: address.toString(),
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1186
1491
|
for (const linkRef in libraries.linkReferences) {
|
|
1187
1492
|
for (const contractName in libraries.linkReferences[linkRef]) {
|
|
1188
1493
|
// If the library name matches the one we just deployed, we replace it.
|
|
@@ -1264,7 +1569,7 @@ export async function deployL1Contract(
|
|
|
1264
1569
|
}
|
|
1265
1570
|
}
|
|
1266
1571
|
|
|
1267
|
-
return { address: EthAddress.fromString(resultingAddress!), txHash };
|
|
1572
|
+
return { address: EthAddress.fromString(resultingAddress!), txHash, deployedLibraries };
|
|
1268
1573
|
}
|
|
1269
1574
|
|
|
1270
1575
|
export function getExpectedAddress(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { toBigIntBE, toHex } from '@aztec/foundation/bigint-buffer';
|
|
2
2
|
import { keccak256 } from '@aztec/foundation/crypto';
|
|
3
|
-
import
|
|
3
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
4
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
5
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
6
|
import type { TestDateProvider } from '@aztec/foundation/timer';
|
|
@@ -112,7 +112,7 @@ export class EthCheatCodes {
|
|
|
112
112
|
* @param account - The account to set the balance for
|
|
113
113
|
* @param balance - The balance to set
|
|
114
114
|
*/
|
|
115
|
-
public async setBalance(account: EthAddress, balance: bigint): Promise<void> {
|
|
115
|
+
public async setBalance(account: EthAddress | Hex, balance: bigint): Promise<void> {
|
|
116
116
|
try {
|
|
117
117
|
await this.rpcCall('anvil_setBalance', [account.toString(), toHex(balance)]);
|
|
118
118
|
} catch (err) {
|
|
@@ -121,6 +121,11 @@ export class EthCheatCodes {
|
|
|
121
121
|
this.logger.warn(`Set balance for ${account} to ${balance}`);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
public async getBalance(account: EthAddress | Hex): Promise<bigint> {
|
|
125
|
+
const res = await this.rpcCall('eth_getBalance', [account.toString(), 'latest']);
|
|
126
|
+
return BigInt(res);
|
|
127
|
+
}
|
|
128
|
+
|
|
124
129
|
/**
|
|
125
130
|
* Set the interval between successive blocks (block time). This does NOT enable interval mining.
|
|
126
131
|
* @param interval - The interval to use between blocks
|
|
@@ -300,6 +305,11 @@ export class EthCheatCodes {
|
|
|
300
305
|
*/
|
|
301
306
|
public async startImpersonating(who: EthAddress | Hex): Promise<void> {
|
|
302
307
|
try {
|
|
308
|
+
// Since the `who` impersonated will sometimes be a contract without funds, we fund it if needed.
|
|
309
|
+
if ((await this.getBalance(who)) === 0n) {
|
|
310
|
+
await this.setBalance(who, 10n * 10n ** 18n);
|
|
311
|
+
}
|
|
312
|
+
|
|
303
313
|
await this.rpcCall('hardhat_impersonateAccount', [who.toString()]);
|
|
304
314
|
} catch (err) {
|
|
305
315
|
throw new Error(`Error impersonating ${who}: ${err}`);
|
|
@@ -258,7 +258,11 @@ export class RollupCheatCodes {
|
|
|
258
258
|
*/
|
|
259
259
|
public async setProvingCostPerMana(ethValue: bigint) {
|
|
260
260
|
await this.asOwner(async (account, rollup) => {
|
|
261
|
-
const hash = await rollup.write.setProvingCostPerMana([ethValue], {
|
|
261
|
+
const hash = await rollup.write.setProvingCostPerMana([ethValue], {
|
|
262
|
+
account,
|
|
263
|
+
chain: this.client.chain,
|
|
264
|
+
gasLimit: 1000000n,
|
|
265
|
+
});
|
|
262
266
|
await this.client.waitForTransactionReceipt({ hash });
|
|
263
267
|
this.logger.warn(`Updated proving cost per mana to ${ethValue}`);
|
|
264
268
|
});
|
package/src/test/tx_delayer.ts
CHANGED
|
@@ -18,7 +18,12 @@ import {
|
|
|
18
18
|
|
|
19
19
|
import { type ViemClient, isExtendedClient } from '../types.js';
|
|
20
20
|
|
|
21
|
-
export function waitUntilBlock<T extends Client>(
|
|
21
|
+
export function waitUntilBlock<T extends Client>(
|
|
22
|
+
client: T,
|
|
23
|
+
blockNumber: number | bigint,
|
|
24
|
+
logger?: Logger,
|
|
25
|
+
timeout?: number,
|
|
26
|
+
) {
|
|
22
27
|
const publicClient =
|
|
23
28
|
'getBlockNumber' in client && typeof client.getBlockNumber === 'function'
|
|
24
29
|
? (client as unknown as PublicClient)
|
|
@@ -31,12 +36,17 @@ export function waitUntilBlock<T extends Client>(client: T, blockNumber: number
|
|
|
31
36
|
return currentBlockNumber >= BigInt(blockNumber);
|
|
32
37
|
},
|
|
33
38
|
`Wait until L1 block ${blockNumber}`,
|
|
34
|
-
120,
|
|
39
|
+
timeout ?? 120,
|
|
35
40
|
0.1,
|
|
36
41
|
);
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
export function waitUntilL1Timestamp<T extends Client>(
|
|
44
|
+
export function waitUntilL1Timestamp<T extends Client>(
|
|
45
|
+
client: T,
|
|
46
|
+
timestamp: number | bigint,
|
|
47
|
+
logger?: Logger,
|
|
48
|
+
timeout?: number,
|
|
49
|
+
) {
|
|
40
50
|
const publicClient =
|
|
41
51
|
'getBlockNumber' in client && typeof client.getBlockNumber === 'function'
|
|
42
52
|
? (client as unknown as PublicClient)
|
|
@@ -56,7 +66,7 @@ export function waitUntilL1Timestamp<T extends Client>(client: T, timestamp: num
|
|
|
56
66
|
return currentTs >= BigInt(timestamp);
|
|
57
67
|
},
|
|
58
68
|
`Wait until L1 timestamp ${timestamp}`,
|
|
59
|
-
120,
|
|
69
|
+
timeout ?? 120,
|
|
60
70
|
0.1,
|
|
61
71
|
);
|
|
62
72
|
}
|