@aztec/ethereum 3.0.0-nightly.20250930 → 3.0.0-nightly.20251002
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.js +2 -2
- package/dest/contracts/fee_asset_handler.d.ts +2 -2
- package/dest/contracts/governance_proposer.d.ts +1 -2
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +1 -2
- package/dest/contracts/multicall.d.ts +0 -2
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +2 -4
- package/dest/contracts/rollup.d.ts +2 -2
- package/dest/deploy_l1_contracts.d.ts +11 -1
- package/dest/deploy_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_l1_contracts.js +174 -54
- package/dest/l1_artifacts.d.ts +1978 -0
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +6 -1
- package/dest/l1_contract_addresses.d.ts +5 -1
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +2 -1
- package/dest/l1_tx_utils/factory.d.ts.map +1 -1
- package/dest/l1_tx_utils/factory.js +2 -2
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +14 -26
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +140 -136
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +4 -11
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +10 -70
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/types.d.ts +15 -2
- package/dest/l1_tx_utils/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/config.ts +2 -2
- package/src/contracts/governance_proposer.ts +3 -4
- package/src/contracts/multicall.ts +4 -4
- package/src/deploy_l1_contracts.ts +161 -51
- package/src/l1_artifacts.ts +8 -0
- package/src/l1_contract_addresses.ts +3 -1
- package/src/l1_tx_utils/factory.ts +2 -2
- package/src/l1_tx_utils/l1_tx_utils.ts +159 -157
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +8 -99
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +1 -1
- package/src/l1_tx_utils/types.ts +16 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/ethereum",
|
|
3
|
-
"version": "3.0.0-nightly.
|
|
3
|
+
"version": "3.0.0-nightly.20251002",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"../package.common.json"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@aztec/blob-lib": "3.0.0-nightly.
|
|
35
|
-
"@aztec/constants": "3.0.0-nightly.
|
|
36
|
-
"@aztec/foundation": "3.0.0-nightly.
|
|
37
|
-
"@aztec/l1-artifacts": "3.0.0-nightly.
|
|
34
|
+
"@aztec/blob-lib": "3.0.0-nightly.20251002",
|
|
35
|
+
"@aztec/constants": "3.0.0-nightly.20251002",
|
|
36
|
+
"@aztec/foundation": "3.0.0-nightly.20251002",
|
|
37
|
+
"@aztec/l1-artifacts": "3.0.0-nightly.20251002",
|
|
38
38
|
"@viem/anvil": "^0.0.10",
|
|
39
39
|
"dotenv": "^16.0.3",
|
|
40
40
|
"lodash.chunk": "^4.2.0",
|
package/src/config.ts
CHANGED
|
@@ -232,8 +232,8 @@ const TestnetEntryQueueConfig = {
|
|
|
232
232
|
};
|
|
233
233
|
|
|
234
234
|
const StagingIgnitionEntryQueueConfig = {
|
|
235
|
-
bootstrapValidatorSetSize:
|
|
236
|
-
bootstrapFlushSize:
|
|
235
|
+
bootstrapValidatorSetSize: 48n,
|
|
236
|
+
bootstrapFlushSize: 48n,
|
|
237
237
|
normalFlushSizeMin: 1n,
|
|
238
238
|
normalFlushSizeQuotient: 2048n,
|
|
239
239
|
maxQueueFlushSize: 24n,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
getContract,
|
|
12
12
|
} from 'viem';
|
|
13
13
|
|
|
14
|
-
import type {
|
|
14
|
+
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
15
15
|
import type { ViemClient } from '../types.js';
|
|
16
16
|
import { type IEmpireBase, encodeSignal, encodeSignalWithSignature, signSignalWithSig } from './empire_base.js';
|
|
17
17
|
import { extractProposalIdFromLogs } from './governance.js';
|
|
@@ -102,10 +102,9 @@ export class GovernanceProposerContract implements IEmpireBase {
|
|
|
102
102
|
l1TxUtils: L1TxUtils,
|
|
103
103
|
): Promise<{
|
|
104
104
|
receipt: TransactionReceipt;
|
|
105
|
-
gasPrice: GasPrice;
|
|
106
105
|
proposalId: bigint;
|
|
107
106
|
}> {
|
|
108
|
-
const { receipt
|
|
107
|
+
const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
|
|
109
108
|
to: this.address.toString(),
|
|
110
109
|
data: encodeFunctionData({
|
|
111
110
|
abi: this.proposer.abi,
|
|
@@ -114,6 +113,6 @@ export class GovernanceProposerContract implements IEmpireBase {
|
|
|
114
113
|
}),
|
|
115
114
|
});
|
|
116
115
|
const proposalId = extractProposalIdFromLogs(receipt.logs);
|
|
117
|
-
return { receipt,
|
|
116
|
+
return { receipt, proposalId };
|
|
118
117
|
}
|
|
119
118
|
}
|
|
@@ -36,7 +36,7 @@ export class Multicall3 {
|
|
|
36
36
|
const encodedForwarderData = encodeFunctionData(forwarderFunctionData);
|
|
37
37
|
|
|
38
38
|
try {
|
|
39
|
-
const { receipt,
|
|
39
|
+
const { receipt, state } = await l1TxUtils.sendAndMonitorTransaction(
|
|
40
40
|
{
|
|
41
41
|
to: MULTI_CALL_3_ADDRESS,
|
|
42
42
|
data: encodedForwarderData,
|
|
@@ -47,7 +47,7 @@ export class Multicall3 {
|
|
|
47
47
|
|
|
48
48
|
if (receipt.status === 'success') {
|
|
49
49
|
const stats = await l1TxUtils.getTransactionStats(receipt.transactionHash);
|
|
50
|
-
return { receipt,
|
|
50
|
+
return { receipt, stats };
|
|
51
51
|
} else {
|
|
52
52
|
logger.error('Forwarder transaction failed', undefined, { receipt });
|
|
53
53
|
|
|
@@ -59,7 +59,7 @@ export class Multicall3 {
|
|
|
59
59
|
let errorMsg: string | undefined;
|
|
60
60
|
|
|
61
61
|
if (blobConfig) {
|
|
62
|
-
const maxFeePerBlobGas = blobConfig.maxFeePerBlobGas ?? gasPrice.maxFeePerBlobGas;
|
|
62
|
+
const maxFeePerBlobGas = blobConfig.maxFeePerBlobGas ?? state.gasPrice.maxFeePerBlobGas;
|
|
63
63
|
if (maxFeePerBlobGas === undefined) {
|
|
64
64
|
errorMsg = 'maxFeePerBlobGas is required to get the error message';
|
|
65
65
|
} else {
|
|
@@ -90,7 +90,7 @@ export class Multicall3 {
|
|
|
90
90
|
errorMsg = await l1TxUtils.tryGetErrorFromRevertedTx(encodedForwarderData, args, undefined, []);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
return { receipt,
|
|
93
|
+
return { receipt, errorMsg };
|
|
94
94
|
}
|
|
95
95
|
} catch (err) {
|
|
96
96
|
if (err instanceof TimeoutError) {
|
|
@@ -45,6 +45,7 @@ import { RegistryContract } from './contracts/registry.js';
|
|
|
45
45
|
import { RollupContract, SlashingProposerType } from './contracts/rollup.js';
|
|
46
46
|
import {
|
|
47
47
|
CoinIssuerArtifact,
|
|
48
|
+
DateGatedRelayerArtifact,
|
|
48
49
|
FeeAssetArtifact,
|
|
49
50
|
FeeAssetHandlerArtifact,
|
|
50
51
|
GSEArtifact,
|
|
@@ -164,6 +165,8 @@ export interface DeployL1ContractsArgs extends Omit<L1ContractsConfig, keyof L1T
|
|
|
164
165
|
realVerifier: boolean;
|
|
165
166
|
/** The zk passport args */
|
|
166
167
|
zkPassportArgs?: ZKPassportArgs;
|
|
168
|
+
/** If provided, use this token for BOTH fee and staking assets (skip deployments) */
|
|
169
|
+
existingTokenAddress?: EthAddress;
|
|
167
170
|
}
|
|
168
171
|
|
|
169
172
|
export interface ZKPassportArgs {
|
|
@@ -175,6 +178,80 @@ export interface ZKPassportArgs {
|
|
|
175
178
|
zkPassportScope?: string;
|
|
176
179
|
}
|
|
177
180
|
|
|
181
|
+
// Minimal ERC20 ABI for validation purposes. We only read view methods.
|
|
182
|
+
const ERC20_VALIDATION_ABI = [
|
|
183
|
+
{
|
|
184
|
+
type: 'function',
|
|
185
|
+
name: 'totalSupply',
|
|
186
|
+
stateMutability: 'view',
|
|
187
|
+
inputs: [],
|
|
188
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
type: 'function',
|
|
192
|
+
name: 'name',
|
|
193
|
+
stateMutability: 'view',
|
|
194
|
+
inputs: [],
|
|
195
|
+
outputs: [{ name: '', type: 'string' }],
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
type: 'function',
|
|
199
|
+
name: 'symbol',
|
|
200
|
+
stateMutability: 'view',
|
|
201
|
+
inputs: [],
|
|
202
|
+
outputs: [{ name: '', type: 'string' }],
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
type: 'function',
|
|
206
|
+
name: 'decimals',
|
|
207
|
+
stateMutability: 'view',
|
|
208
|
+
inputs: [],
|
|
209
|
+
outputs: [{ name: '', type: 'uint8' }],
|
|
210
|
+
},
|
|
211
|
+
] as const;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Validates that the provided address points to a contract that resembles an ERC20 token.
|
|
215
|
+
* Checks for contract code and attempts common ERC20 view calls.
|
|
216
|
+
* Throws an error if validation fails.
|
|
217
|
+
*/
|
|
218
|
+
export async function validateExistingErc20TokenAddress(
|
|
219
|
+
l1Client: ExtendedViemWalletClient,
|
|
220
|
+
tokenAddress: EthAddress,
|
|
221
|
+
logger: Logger,
|
|
222
|
+
): Promise<void> {
|
|
223
|
+
const addressString = tokenAddress.toString();
|
|
224
|
+
|
|
225
|
+
// Ensure there is contract code at the address
|
|
226
|
+
const code = await l1Client.getCode({ address: addressString });
|
|
227
|
+
if (!code || code === '0x') {
|
|
228
|
+
throw new Error(`No contract code found at provided token address ${addressString}`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const contract = getContract({
|
|
232
|
+
address: getAddress(addressString),
|
|
233
|
+
abi: ERC20_VALIDATION_ABI,
|
|
234
|
+
client: l1Client,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Validate all required ERC20 methods in parallel
|
|
238
|
+
const checks = [
|
|
239
|
+
contract.read.totalSupply().then(total => typeof total === 'bigint'),
|
|
240
|
+
contract.read.name().then(() => true),
|
|
241
|
+
contract.read.symbol().then(() => true),
|
|
242
|
+
contract.read.decimals().then(dec => typeof dec === 'number' || typeof dec === 'bigint'),
|
|
243
|
+
];
|
|
244
|
+
|
|
245
|
+
const results = await Promise.allSettled(checks);
|
|
246
|
+
const failedChecks = results.filter(result => result.status === 'rejected' || result.value !== true);
|
|
247
|
+
|
|
248
|
+
if (failedChecks.length > 0) {
|
|
249
|
+
throw new Error(`Address ${addressString} does not appear to implement ERC20 view methods`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
logger.verbose(`Validated existing token at ${addressString} appears to be ERC20-compatible`);
|
|
253
|
+
}
|
|
254
|
+
|
|
178
255
|
export const deploySharedContracts = async (
|
|
179
256
|
l1Client: ExtendedViemWalletClient,
|
|
180
257
|
deployer: L1Deployer,
|
|
@@ -187,19 +264,22 @@ export const deploySharedContracts = async (
|
|
|
187
264
|
|
|
188
265
|
const txHashes: Hex[] = [];
|
|
189
266
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
l1Client.
|
|
194
|
-
|
|
195
|
-
|
|
267
|
+
let feeAssetAddress: EthAddress;
|
|
268
|
+
let stakingAssetAddress: EthAddress;
|
|
269
|
+
if (args.existingTokenAddress) {
|
|
270
|
+
await validateExistingErc20TokenAddress(l1Client, args.existingTokenAddress, logger);
|
|
271
|
+
feeAssetAddress = args.existingTokenAddress;
|
|
272
|
+
stakingAssetAddress = args.existingTokenAddress;
|
|
273
|
+
logger.verbose(`Using existing token for fee and staking assets at ${args.existingTokenAddress}`);
|
|
274
|
+
} else {
|
|
275
|
+
const deployedFee = await deployer.deploy(FeeAssetArtifact, ['FeeJuice', 'FEE', l1Client.account.address]);
|
|
276
|
+
feeAssetAddress = deployedFee.address;
|
|
277
|
+
logger.verbose(`Deployed Fee Asset at ${feeAssetAddress}`);
|
|
196
278
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
]);
|
|
202
|
-
logger.verbose(`Deployed Staking Asset at ${stakingAssetAddress}`);
|
|
279
|
+
const deployedStaking = await deployer.deploy(StakingAssetArtifact, ['Staking', 'STK', l1Client.account.address]);
|
|
280
|
+
stakingAssetAddress = deployedStaking.address;
|
|
281
|
+
logger.verbose(`Deployed Staking Asset at ${stakingAssetAddress}`);
|
|
282
|
+
}
|
|
203
283
|
|
|
204
284
|
const gseAddress = (
|
|
205
285
|
await deployer.deploy(GSEArtifact, [
|
|
@@ -287,8 +367,8 @@ export const deploySharedContracts = async (
|
|
|
287
367
|
let stakingAssetHandlerAddress: EthAddress | undefined = undefined;
|
|
288
368
|
let zkPassportVerifierAddress: EthAddress | undefined = undefined;
|
|
289
369
|
|
|
290
|
-
// Only if not on mainnet will we deploy the handlers
|
|
291
|
-
if (l1Client.chain.id !== 1) {
|
|
370
|
+
// Only if not on mainnet will we deploy the handlers, and only when we control the token
|
|
371
|
+
if (l1Client.chain.id !== 1 && !args.existingTokenAddress) {
|
|
292
372
|
/* -------------------------------------------------------------------------- */
|
|
293
373
|
/* CHEAT CODES START HERE */
|
|
294
374
|
/* -------------------------------------------------------------------------- */
|
|
@@ -379,19 +459,23 @@ export const deploySharedContracts = async (
|
|
|
379
459
|
|
|
380
460
|
const rewardDistributorAddress = await registry.getRewardDistributor();
|
|
381
461
|
|
|
382
|
-
|
|
462
|
+
if (!args.existingTokenAddress) {
|
|
463
|
+
const blockReward = getRewardConfig(networkName).blockReward;
|
|
383
464
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
465
|
+
const funding = blockReward * 200000n;
|
|
466
|
+
const { txHash: fundRewardDistributorTxHash } = await deployer.sendTransaction({
|
|
467
|
+
to: feeAssetAddress.toString(),
|
|
468
|
+
data: encodeFunctionData({
|
|
469
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
470
|
+
functionName: 'mint',
|
|
471
|
+
args: [rewardDistributorAddress.toString(), funding],
|
|
472
|
+
}),
|
|
473
|
+
});
|
|
393
474
|
|
|
394
|
-
|
|
475
|
+
logger.verbose(`Funded reward distributor with ${funding} fee asset in ${fundRewardDistributorTxHash}`);
|
|
476
|
+
} else {
|
|
477
|
+
logger.verbose(`Skipping reward distributor funding as existing token is provided`);
|
|
478
|
+
}
|
|
395
479
|
|
|
396
480
|
/* -------------------------------------------------------------------------- */
|
|
397
481
|
/* FUND REWARD DISTRIBUTOR STOP */
|
|
@@ -610,21 +694,26 @@ export const deployRollup = async (
|
|
|
610
694
|
logger.verbose(`All core contracts have been deployed`);
|
|
611
695
|
|
|
612
696
|
if (args.feeJuicePortalInitialBalance && args.feeJuicePortalInitialBalance > 0n) {
|
|
613
|
-
|
|
697
|
+
// Skip funding when using an external token, as we likely don't have mint permissions
|
|
698
|
+
if (!('existingTokenAddress' in args) || !args.existingTokenAddress) {
|
|
699
|
+
const feeJuicePortalAddress = await rollupContract.getFeeJuicePortal();
|
|
614
700
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
701
|
+
// In fast mode, use the L1TxUtils to send transactions with nonce management
|
|
702
|
+
const { txHash: mintTxHash } = await deployer.sendTransaction({
|
|
703
|
+
to: addresses.feeJuiceAddress.toString(),
|
|
704
|
+
data: encodeFunctionData({
|
|
705
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
706
|
+
functionName: 'mint',
|
|
707
|
+
args: [feeJuicePortalAddress.toString(), args.feeJuicePortalInitialBalance],
|
|
708
|
+
}),
|
|
709
|
+
});
|
|
710
|
+
logger.verbose(
|
|
711
|
+
`Funding fee juice portal with ${args.feeJuicePortalInitialBalance} fee juice in ${mintTxHash} (accelerated test deployments)`,
|
|
712
|
+
);
|
|
713
|
+
txHashes.push(mintTxHash);
|
|
714
|
+
} else {
|
|
715
|
+
logger.verbose('Skipping fee juice portal funding due to external token usage');
|
|
716
|
+
}
|
|
628
717
|
}
|
|
629
718
|
|
|
630
719
|
const slashFactoryAddress = (await deployer.deploy(SlashFactoryArtifact, [rollupAddress.toString()])).address;
|
|
@@ -747,6 +836,7 @@ export const handoverToGovernance = async (
|
|
|
747
836
|
governanceAddress: EthAddress,
|
|
748
837
|
logger: Logger,
|
|
749
838
|
acceleratedTestDeployments: boolean | undefined,
|
|
839
|
+
useExternalToken: boolean = false,
|
|
750
840
|
) => {
|
|
751
841
|
// We need to call a function on the registry to set the various contract addresses.
|
|
752
842
|
const registryContract = getContract({
|
|
@@ -812,7 +902,10 @@ export const handoverToGovernance = async (
|
|
|
812
902
|
txHashes.push(transferOwnershipTxHash);
|
|
813
903
|
}
|
|
814
904
|
|
|
815
|
-
if (
|
|
905
|
+
if (
|
|
906
|
+
!useExternalToken &&
|
|
907
|
+
(acceleratedTestDeployments || (await feeAsset.read.owner()) !== coinIssuerAddress.toString())
|
|
908
|
+
) {
|
|
816
909
|
const { txHash } = await deployer.sendTransaction(
|
|
817
910
|
{
|
|
818
911
|
to: feeAssetAddress.toString(),
|
|
@@ -839,23 +932,28 @@ export const handoverToGovernance = async (
|
|
|
839
932
|
);
|
|
840
933
|
logger.verbose(`Accept ownership of fee asset in ${acceptTokenOwnershipTxHash}`);
|
|
841
934
|
txHashes.push(acceptTokenOwnershipTxHash);
|
|
935
|
+
} else if (useExternalToken) {
|
|
936
|
+
logger.verbose('Skipping fee asset ownership transfer due to external token usage');
|
|
842
937
|
}
|
|
843
938
|
|
|
939
|
+
// Either deploy or at least predict the address of the date gated relayer
|
|
940
|
+
const dateGatedRelayer = await deployer.deploy(DateGatedRelayerArtifact, [
|
|
941
|
+
governanceAddress.toString(),
|
|
942
|
+
1798761600n, // 2027-01-01 00:00:00 UTC
|
|
943
|
+
]);
|
|
944
|
+
|
|
844
945
|
// If the owner is not the Governance contract, transfer ownership to the Governance contract
|
|
845
|
-
if (
|
|
846
|
-
acceleratedTestDeployments ||
|
|
847
|
-
(await coinIssuerContract.read.owner()) !== getAddress(governanceAddress.toString())
|
|
848
|
-
) {
|
|
946
|
+
if (acceleratedTestDeployments || (await coinIssuerContract.read.owner()) === deployer.client.account.address) {
|
|
849
947
|
const { txHash: transferOwnershipTxHash } = await deployer.sendTransaction({
|
|
850
948
|
to: coinIssuerContract.address,
|
|
851
949
|
data: encodeFunctionData({
|
|
852
950
|
abi: CoinIssuerArtifact.contractAbi,
|
|
853
951
|
functionName: 'transferOwnership',
|
|
854
|
-
args: [getAddress(
|
|
952
|
+
args: [getAddress(dateGatedRelayer.address.toString())],
|
|
855
953
|
}),
|
|
856
954
|
});
|
|
857
955
|
logger.verbose(
|
|
858
|
-
`Transferring the ownership of the coin issuer contract at ${coinIssuerAddress} to the
|
|
956
|
+
`Transferring the ownership of the coin issuer contract at ${coinIssuerAddress} to the DateGatedRelayer ${dateGatedRelayer.address} in tx ${transferOwnershipTxHash}`,
|
|
859
957
|
);
|
|
860
958
|
txHashes.push(transferOwnershipTxHash);
|
|
861
959
|
}
|
|
@@ -863,6 +961,8 @@ export const handoverToGovernance = async (
|
|
|
863
961
|
// Wait for all actions to be mined
|
|
864
962
|
await deployer.waitForDeployments();
|
|
865
963
|
await Promise.all(txHashes.map(txHash => extendedClient.waitForTransactionReceipt({ hash: txHash })));
|
|
964
|
+
|
|
965
|
+
return { dateGatedRelayerAddress: dateGatedRelayer.address };
|
|
866
966
|
};
|
|
867
967
|
|
|
868
968
|
/*
|
|
@@ -1079,6 +1179,13 @@ export const deployL1Contracts = async (
|
|
|
1079
1179
|
logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`);
|
|
1080
1180
|
validateConfig(args);
|
|
1081
1181
|
|
|
1182
|
+
if (args.initialValidators && args.initialValidators.length > 0 && args.existingTokenAddress) {
|
|
1183
|
+
throw new Error(
|
|
1184
|
+
'Cannot deploy with both initialValidators and existingTokenAddress. ' +
|
|
1185
|
+
'Initial validator funding requires minting tokens, which is not possible with an external token.',
|
|
1186
|
+
);
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1082
1189
|
const l1Client = createExtendedL1Client(rpcUrls, account, chain);
|
|
1083
1190
|
|
|
1084
1191
|
// Deploy multicall3 if it does not exist in this network
|
|
@@ -1148,7 +1255,7 @@ export const deployL1Contracts = async (
|
|
|
1148
1255
|
await deployer.waitForDeployments();
|
|
1149
1256
|
|
|
1150
1257
|
// Now that the rollup has been deployed and added to the registry, transfer ownership to governance
|
|
1151
|
-
await handoverToGovernance(
|
|
1258
|
+
const { dateGatedRelayerAddress } = await handoverToGovernance(
|
|
1152
1259
|
l1Client,
|
|
1153
1260
|
deployer,
|
|
1154
1261
|
registryAddress,
|
|
@@ -1158,6 +1265,7 @@ export const deployL1Contracts = async (
|
|
|
1158
1265
|
governanceAddress,
|
|
1159
1266
|
logger,
|
|
1160
1267
|
args.acceleratedTestDeployments,
|
|
1268
|
+
!!args.existingTokenAddress,
|
|
1161
1269
|
);
|
|
1162
1270
|
|
|
1163
1271
|
logger.info(`Handing over to governance complete`);
|
|
@@ -1342,6 +1450,7 @@ export const deployL1Contracts = async (
|
|
|
1342
1450
|
stakingAssetHandlerAddress,
|
|
1343
1451
|
zkPassportVerifierAddress,
|
|
1344
1452
|
coinIssuerAddress,
|
|
1453
|
+
dateGatedRelayerAddress,
|
|
1345
1454
|
},
|
|
1346
1455
|
};
|
|
1347
1456
|
};
|
|
@@ -1449,11 +1558,14 @@ export class L1Deployer {
|
|
|
1449
1558
|
tx: L1TxRequest,
|
|
1450
1559
|
options?: L1GasConfig,
|
|
1451
1560
|
): Promise<{ txHash: Hex; gasLimit: bigint; gasPrice: GasPrice }> {
|
|
1452
|
-
return this.l1TxUtils.sendTransaction(tx, options)
|
|
1561
|
+
return this.l1TxUtils.sendTransaction(tx, options).then(({ txHash, state }) => ({
|
|
1562
|
+
txHash,
|
|
1563
|
+
gasLimit: state.gasLimit,
|
|
1564
|
+
gasPrice: state.gasPrice,
|
|
1565
|
+
}));
|
|
1453
1566
|
}
|
|
1454
1567
|
}
|
|
1455
1568
|
|
|
1456
|
-
// docs:start:deployL1Contract
|
|
1457
1569
|
/**
|
|
1458
1570
|
* Helper function to deploy ETH contracts.
|
|
1459
1571
|
* @param walletClient - A viem WalletClient.
|
|
@@ -1650,5 +1762,3 @@ export function getExpectedAddress(
|
|
|
1650
1762
|
calldata,
|
|
1651
1763
|
};
|
|
1652
1764
|
}
|
|
1653
|
-
|
|
1654
|
-
// docs:end:deployL1Contract
|
package/src/l1_artifacts.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CoinIssuerAbi,
|
|
3
3
|
CoinIssuerBytecode,
|
|
4
|
+
DateGatedRelayerAbi,
|
|
5
|
+
DateGatedRelayerBytecode,
|
|
4
6
|
EmpireSlasherDeploymentExtLibAbi,
|
|
5
7
|
EmpireSlasherDeploymentExtLibBytecode,
|
|
6
8
|
EmpireSlashingProposerAbi,
|
|
@@ -149,6 +151,12 @@ export const CoinIssuerArtifact = {
|
|
|
149
151
|
contractBytecode: CoinIssuerBytecode as Hex,
|
|
150
152
|
};
|
|
151
153
|
|
|
154
|
+
export const DateGatedRelayerArtifact = {
|
|
155
|
+
name: 'DateGatedRelayer',
|
|
156
|
+
contractAbi: DateGatedRelayerAbi,
|
|
157
|
+
contractBytecode: DateGatedRelayerBytecode as Hex,
|
|
158
|
+
};
|
|
159
|
+
|
|
152
160
|
export const GovernanceProposerArtifact = {
|
|
153
161
|
name: 'GovernanceProposer',
|
|
154
162
|
contractAbi: GovernanceProposerAbi,
|
|
@@ -32,6 +32,7 @@ export type L1ContractAddresses = {
|
|
|
32
32
|
stakingAssetHandlerAddress?: EthAddress | undefined;
|
|
33
33
|
zkPassportVerifierAddress?: EthAddress | undefined;
|
|
34
34
|
gseAddress?: EthAddress | undefined;
|
|
35
|
+
dateGatedRelayerAddress?: EthAddress | undefined;
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
export const L1ContractAddressesSchema = z.object({
|
|
@@ -51,12 +52,13 @@ export const L1ContractAddressesSchema = z.object({
|
|
|
51
52
|
stakingAssetHandlerAddress: schemas.EthAddress.optional(),
|
|
52
53
|
zkPassportVerifierAddress: schemas.EthAddress.optional(),
|
|
53
54
|
gseAddress: schemas.EthAddress.optional(),
|
|
55
|
+
dateGatedRelayerAddress: schemas.EthAddress.optional(),
|
|
54
56
|
}) satisfies ZodFor<L1ContractAddresses>;
|
|
55
57
|
|
|
56
58
|
const parseEnv = (val: string) => EthAddress.fromString(val);
|
|
57
59
|
|
|
58
60
|
export const l1ContractAddressesMapping: ConfigMappingsType<
|
|
59
|
-
Omit<L1ContractAddresses, 'gseAddress' | 'zkPassportVerifierAddress'>
|
|
61
|
+
Omit<L1ContractAddresses, 'gseAddress' | 'zkPassportVerifierAddress' | 'dateGatedRelayerAddress'>
|
|
60
62
|
> = {
|
|
61
63
|
registryAddress: {
|
|
62
64
|
env: 'REGISTRY_CONTRACT_ADDRESS',
|
|
@@ -13,7 +13,7 @@ import type { SigningCallback } from './types.js';
|
|
|
13
13
|
|
|
14
14
|
export function createL1TxUtilsFromViemWallet(
|
|
15
15
|
client: ExtendedViemWalletClient,
|
|
16
|
-
logger: Logger = createLogger('
|
|
16
|
+
logger: Logger = createLogger('l1-tx-utils'),
|
|
17
17
|
dateProvider: DateProvider = new DateProvider(),
|
|
18
18
|
config?: Partial<L1TxUtilsConfig>,
|
|
19
19
|
debugMaxGasLimit: boolean = false,
|
|
@@ -32,7 +32,7 @@ export function createL1TxUtilsFromViemWallet(
|
|
|
32
32
|
export function createL1TxUtilsFromEthSigner(
|
|
33
33
|
client: ViemClient,
|
|
34
34
|
signer: EthSigner,
|
|
35
|
-
logger: Logger = createLogger('
|
|
35
|
+
logger: Logger = createLogger('l1-tx-utils'),
|
|
36
36
|
dateProvider: DateProvider = new DateProvider(),
|
|
37
37
|
config?: Partial<L1TxUtilsConfig>,
|
|
38
38
|
debugMaxGasLimit: boolean = false,
|