@aztec/ethereum 3.0.0-devnet.2 → 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 +1 -1
- package/dest/config.d.ts +7 -4
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +55 -17
- package/dest/constants.d.ts +1 -1
- package/dest/contracts/empire_base.d.ts +6 -5
- 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 +5 -4
- package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.js +8 -2
- 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 +1 -1
- 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_proposer.d.ts +5 -4
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +8 -2
- 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 +2 -2
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/registry.d.ts +1 -1
- package/dest/contracts/registry.d.ts.map +1 -1
- package/dest/contracts/rollup.d.ts +55 -64
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +76 -67
- package/dest/contracts/slasher_contract.d.ts +1 -1
- package/dest/contracts/slasher_contract.d.ts.map +1 -1
- package/dest/contracts/tally_slashing_proposer.d.ts +9 -7
- package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/tally_slashing_proposer.js +4 -4
- package/dest/contracts/utils.d.ts +1 -1
- package/dest/deploy_l1_contracts.d.ts +456 -9
- package/dest/deploy_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_l1_contracts.js +68 -37
- 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 +6400 -872
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_contract_addresses.d.ts +3 -3
- package/dest/l1_reader.d.ts +3 -1
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +6 -0
- package/dest/l1_tx_utils/config.d.ts +5 -5
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +32 -9
- package/dest/l1_tx_utils/constants.d.ts +1 -1
- package/dest/l1_tx_utils/factory.d.ts +1 -1
- 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 +1 -1
- package/dest/l1_tx_utils/interfaces.d.ts +2 -2
- package/dest/l1_tx_utils/interfaces.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +1 -2
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +17 -4
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +1 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +29 -16
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +171 -34
- package/dest/l1_tx_utils/signer.d.ts +1 -1
- package/dest/l1_tx_utils/types.d.ts +1 -1
- package/dest/l1_tx_utils/types.d.ts.map +1 -1
- package/dest/l1_tx_utils/utils.d.ts +1 -1
- package/dest/l1_types.d.ts +1 -1
- package/dest/publisher_manager.d.ts +1 -1
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/queries.d.ts +1 -1
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +5 -3
- package/dest/test/chain_monitor.d.ts +27 -24
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +32 -34
- package/dest/test/delayed_tx_utils.d.ts +1 -1
- package/dest/test/delayed_tx_utils.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.d.ts +8 -12
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +9 -3
- 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 +14 -13
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +43 -38
- 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/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/zkPassportVerifierAddress.d.ts +1 -1
- package/package.json +27 -13
- package/src/config.ts +62 -18
- package/src/contracts/empire_base.ts +6 -5
- package/src/contracts/empire_slashing_proposer.ts +11 -5
- package/src/contracts/governance_proposer.ts +11 -5
- package/src/contracts/rollup.ts +81 -80
- package/src/contracts/tally_slashing_proposer.ts +11 -8
- package/src/deploy_l1_contracts.ts +63 -32
- package/src/forwarder_proxy.ts +108 -0
- package/src/l1_reader.ts +8 -0
- package/src/l1_tx_utils/config.ts +34 -13
- 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/interfaces.ts +1 -1
- package/src/l1_tx_utils/l1_tx_utils.ts +24 -4
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +223 -38
- package/src/queries.ts +6 -3
- package/src/test/chain_monitor.ts +50 -48
- package/src/test/eth_cheat_codes.ts +8 -2
- package/src/test/rollup_cheat_codes.ts +44 -42
- package/src/test/start_anvil.ts +2 -0
- package/src/test/tx_delayer.ts +4 -2
- package/src/types.ts +62 -0
- package/src/utils.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/src/index.ts +0 -17
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { L1TxRequest } from '@aztec/ethereum/l1-tx-utils';
|
|
2
|
+
import type { ViemClient } from '@aztec/ethereum/types';
|
|
3
|
+
import { tryExtractEvent } from '@aztec/ethereum/utils';
|
|
4
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
5
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
3
6
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
7
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
@@ -97,8 +100,8 @@ export class TallySlashingProposerContract {
|
|
|
97
100
|
* @param slot - The slot number to check at
|
|
98
101
|
* @returns Whether the round is ready to execute
|
|
99
102
|
*/
|
|
100
|
-
public async isRoundReadyToExecute(round: bigint, slot:
|
|
101
|
-
return await this.contract.read.isRoundReadyToExecute([round, slot]);
|
|
103
|
+
public async isRoundReadyToExecute(round: bigint, slot: SlotNumber): Promise<boolean> {
|
|
104
|
+
return await this.contract.read.isRoundReadyToExecute([round, BigInt(slot)]);
|
|
102
105
|
}
|
|
103
106
|
|
|
104
107
|
/** Returns the slash actions and payload address for a given round (zero if no slash actions) */
|
|
@@ -149,7 +152,7 @@ export class TallySlashingProposerContract {
|
|
|
149
152
|
*/
|
|
150
153
|
public async buildVoteRequestFromSigner(
|
|
151
154
|
votes: Hex,
|
|
152
|
-
slot:
|
|
155
|
+
slot: SlotNumber,
|
|
153
156
|
signer: (msg: TypedDataDefinition) => Promise<Hex>,
|
|
154
157
|
): Promise<L1TxRequest> {
|
|
155
158
|
const typedData = this.buildVoteTypedData(votes, slot);
|
|
@@ -166,7 +169,7 @@ export class TallySlashingProposerContract {
|
|
|
166
169
|
}
|
|
167
170
|
|
|
168
171
|
/** Returns the typed data definition to EIP712-sign for voting */
|
|
169
|
-
public buildVoteTypedData(votes: Hex, slot:
|
|
172
|
+
public buildVoteTypedData(votes: Hex, slot: SlotNumber): TypedDataDefinition {
|
|
170
173
|
const domain = {
|
|
171
174
|
name: 'TallySlashingProposer',
|
|
172
175
|
version: '1',
|
|
@@ -187,12 +190,12 @@ export class TallySlashingProposerContract {
|
|
|
187
190
|
],
|
|
188
191
|
};
|
|
189
192
|
|
|
190
|
-
return { domain, types, primaryType: 'Vote', message: { votes, slot } };
|
|
193
|
+
return { domain, types, primaryType: 'Vote', message: { votes, slot: BigInt(slot) } };
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
/** Gets the digest to sign for voting directly from the contract */
|
|
194
|
-
public async getVoteDataDigest(votes: Hex, slot:
|
|
195
|
-
return Buffer32.fromString(await this.contract.read.getVoteSignatureDigest([votes, slot]));
|
|
197
|
+
public async getVoteDataDigest(votes: Hex, slot: SlotNumber): Promise<Buffer32> {
|
|
198
|
+
return Buffer32.fromString(await this.contract.read.getVoteSignatureDigest([votes, BigInt(slot)]));
|
|
196
199
|
}
|
|
197
200
|
|
|
198
201
|
/**
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/constants';
|
|
2
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import { SecretValue, getActiveNetworkName } from '@aztec/foundation/config';
|
|
3
|
-
import { keccak256String } from '@aztec/foundation/crypto';
|
|
4
|
+
import { keccak256String } from '@aztec/foundation/crypto/keccak';
|
|
5
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
6
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
|
-
import type { Fr } from '@aztec/foundation/fields';
|
|
6
7
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
7
8
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
8
9
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
9
10
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
10
11
|
|
|
11
12
|
import type { Abi, Narrow } from 'abitype';
|
|
12
|
-
import
|
|
13
|
+
import fs from 'fs';
|
|
13
14
|
import chunk from 'lodash.chunk';
|
|
14
15
|
import {
|
|
15
16
|
type Chain,
|
|
@@ -276,6 +277,25 @@ export const deploySharedContracts = async (
|
|
|
276
277
|
feeAssetAddress = deployedFee.address;
|
|
277
278
|
logger.verbose(`Deployed Fee Asset at ${feeAssetAddress}`);
|
|
278
279
|
|
|
280
|
+
// Mint a tiny bit of tokens to satisfy coin-issuer constraints
|
|
281
|
+
const { txHash } = await deployer.sendTransaction(
|
|
282
|
+
{
|
|
283
|
+
to: feeAssetAddress.toString(),
|
|
284
|
+
data: encodeFunctionData({
|
|
285
|
+
abi: FeeAssetArtifact.contractAbi,
|
|
286
|
+
functionName: 'mint',
|
|
287
|
+
args: [l1Client.account.address, 1n * 10n ** 18n],
|
|
288
|
+
}),
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
// contract may not have been deployed yet (CREATE2 returns address before mining),
|
|
292
|
+
// which causes gas estimation to fail. Hardcode to 100k which is plenty for ERC20 mint.
|
|
293
|
+
gasLimit: 100_000n,
|
|
294
|
+
},
|
|
295
|
+
);
|
|
296
|
+
await l1Client.waitForTransactionReceipt({ hash: txHash });
|
|
297
|
+
logger.verbose(`Minted tiny bit of tokens to satisfy coin-issuer constraints in ${txHash}`);
|
|
298
|
+
|
|
279
299
|
const deployedStaking = await deployer.deploy(StakingAssetArtifact, ['Staking', 'STK', l1Client.account.address]);
|
|
280
300
|
stakingAssetAddress = deployedStaking.address;
|
|
281
301
|
logger.verbose(`Deployed Staking Asset at ${stakingAssetAddress}`);
|
|
@@ -351,12 +371,19 @@ export const deploySharedContracts = async (
|
|
|
351
371
|
txHashes.push(txHash);
|
|
352
372
|
}
|
|
353
373
|
|
|
374
|
+
logger.verbose(`Waiting for deployments to complete`);
|
|
375
|
+
await deployer.waitForDeployments();
|
|
376
|
+
|
|
354
377
|
const coinIssuerAddress = (
|
|
355
|
-
await deployer.deploy(
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
378
|
+
await deployer.deploy(
|
|
379
|
+
CoinIssuerArtifact,
|
|
380
|
+
[
|
|
381
|
+
feeAssetAddress.toString(),
|
|
382
|
+
2n * 10n ** 17n, // hard cap of 20% per year
|
|
383
|
+
l1Client.account.address,
|
|
384
|
+
],
|
|
385
|
+
{ gasLimit: 1_000_000n, noSimulation: true },
|
|
386
|
+
)
|
|
360
387
|
).address;
|
|
361
388
|
logger.verbose(`Deployed CoinIssuer at ${coinIssuerAddress}`);
|
|
362
389
|
|
|
@@ -375,17 +402,16 @@ export const deploySharedContracts = async (
|
|
|
375
402
|
/* CHEAT CODES START HERE */
|
|
376
403
|
/* -------------------------------------------------------------------------- */
|
|
377
404
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
).address;
|
|
405
|
+
const deployedFeeAssetHandler = await deployer.deploy(FeeAssetHandlerArtifact, [
|
|
406
|
+
l1Client.account.address,
|
|
407
|
+
feeAssetAddress.toString(),
|
|
408
|
+
BigInt(1000n * 10n ** 18n),
|
|
409
|
+
]);
|
|
410
|
+
feeAssetHandlerAddress = deployedFeeAssetHandler.address;
|
|
385
411
|
logger.verbose(`Deployed FeeAssetHandler at ${feeAssetHandlerAddress}`);
|
|
386
412
|
|
|
387
|
-
// Only
|
|
388
|
-
if (
|
|
413
|
+
// Only add as minter if this is a new deployment (not reusing existing handler from failed previous run)
|
|
414
|
+
if (!deployedFeeAssetHandler.existed) {
|
|
389
415
|
const { txHash } = await deployer.sendTransaction({
|
|
390
416
|
to: feeAssetAddress.toString(),
|
|
391
417
|
data: encodeFunctionData({
|
|
@@ -462,9 +488,9 @@ export const deploySharedContracts = async (
|
|
|
462
488
|
const rewardDistributorAddress = await registry.getRewardDistributor();
|
|
463
489
|
|
|
464
490
|
if (!args.existingTokenAddress) {
|
|
465
|
-
const
|
|
491
|
+
const checkpointReward = getRewardConfig(networkName).checkpointReward;
|
|
466
492
|
|
|
467
|
-
const funding =
|
|
493
|
+
const funding = checkpointReward * 200000n;
|
|
468
494
|
const { txHash: fundRewardDistributorTxHash } = await deployer.sendTransaction({
|
|
469
495
|
to: feeAssetAddress.toString(),
|
|
470
496
|
data: encodeFunctionData({
|
|
@@ -693,7 +719,7 @@ async function writeVerificationJson(
|
|
|
693
719
|
const date = new Date();
|
|
694
720
|
const formattedDate = date.toISOString().slice(2, 19).replace(/[-T:]/g, '');
|
|
695
721
|
// Ensure the verification output directory exists
|
|
696
|
-
await mkdir(outputDirectory, { recursive: true });
|
|
722
|
+
await fs.promises.mkdir(outputDirectory, { recursive: true });
|
|
697
723
|
const suffix = filenameSuffix ? `-${filenameSuffix}` : '';
|
|
698
724
|
const verificationOutputPath = `${outputDirectory}/l1-verify${suffix}-${chainId}-${formattedDate.slice(0, 6)}-${formattedDate.slice(6)}.json`;
|
|
699
725
|
const networkName = getActiveNetworkName();
|
|
@@ -702,7 +728,7 @@ async function writeVerificationJson(
|
|
|
702
728
|
network: networkName,
|
|
703
729
|
records: deployer.verificationRecords,
|
|
704
730
|
};
|
|
705
|
-
await writeFile(verificationOutputPath, JSON.stringify(verificationData, null, 2));
|
|
731
|
+
await fs.promises.writeFile(verificationOutputPath, JSON.stringify(verificationData, null, 2));
|
|
706
732
|
logger.info(`Wrote L1 verification data to ${verificationOutputPath}`);
|
|
707
733
|
} catch (e) {
|
|
708
734
|
logger.warn(`Failed to write L1 verification data file: ${String(e)}`);
|
|
@@ -838,7 +864,8 @@ export const deployRollup = async (
|
|
|
838
864
|
aztecSlotDuration: BigInt(args.aztecSlotDuration),
|
|
839
865
|
aztecEpochDuration: BigInt(args.aztecEpochDuration),
|
|
840
866
|
targetCommitteeSize: BigInt(args.aztecTargetCommitteeSize),
|
|
841
|
-
|
|
867
|
+
lagInEpochsForValidatorSet: BigInt(args.lagInEpochsForValidatorSet),
|
|
868
|
+
lagInEpochsForRandao: BigInt(args.lagInEpochsForRandao),
|
|
842
869
|
aztecProofSubmissionEpochs: BigInt(args.aztecProofSubmissionEpochs),
|
|
843
870
|
slashingQuorum: BigInt(args.slashingQuorum ?? (args.slashingRoundSizeInEpochs * args.aztecEpochDuration) / 2 + 1),
|
|
844
871
|
slashingRoundSize: BigInt(args.slashingRoundSizeInEpochs * args.aztecEpochDuration),
|
|
@@ -1493,13 +1520,13 @@ export const deployL1Contracts = async (
|
|
|
1493
1520
|
// Need to get the time
|
|
1494
1521
|
const currentSlot = await rollup.getSlotNumber();
|
|
1495
1522
|
|
|
1496
|
-
if (
|
|
1497
|
-
const ts = Number(await rollup.getTimestampForSlot(
|
|
1523
|
+
if (currentSlot === 0) {
|
|
1524
|
+
const ts = Number(await rollup.getTimestampForSlot(SlotNumber(1)));
|
|
1498
1525
|
await rpcCall('evm_setNextBlockTimestamp', [ts]);
|
|
1499
1526
|
await rpcCall('hardhat_mine', [1]);
|
|
1500
1527
|
const currentSlot = await rollup.getSlotNumber();
|
|
1501
1528
|
|
|
1502
|
-
if (
|
|
1529
|
+
if (currentSlot !== 1) {
|
|
1503
1530
|
throw new Error(`Error jumping time: current slot is ${currentSlot}`);
|
|
1504
1531
|
}
|
|
1505
1532
|
logger.info(`Jumped to slot 1`);
|
|
@@ -1550,7 +1577,7 @@ export class L1Deployer {
|
|
|
1550
1577
|
async deploy<const TAbi extends Abi>(
|
|
1551
1578
|
params: ContractArtifacts<TAbi>,
|
|
1552
1579
|
args?: ContractConstructorArgs<TAbi>,
|
|
1553
|
-
opts: { gasLimit?: bigint } = {},
|
|
1580
|
+
opts: { gasLimit?: bigint; noSimulation?: boolean } = {},
|
|
1554
1581
|
): Promise<{ address: EthAddress; existed: boolean }> {
|
|
1555
1582
|
this.logger.debug(`Deploying ${params.name} contract`, { args });
|
|
1556
1583
|
try {
|
|
@@ -1566,6 +1593,7 @@ export class L1Deployer {
|
|
|
1566
1593
|
l1TxUtils: this.l1TxUtils,
|
|
1567
1594
|
acceleratedTestDeployments: this.acceleratedTestDeployments,
|
|
1568
1595
|
gasLimit: opts.gasLimit,
|
|
1596
|
+
noSimulation: opts.noSimulation,
|
|
1569
1597
|
},
|
|
1570
1598
|
);
|
|
1571
1599
|
if (txHash) {
|
|
@@ -1655,6 +1683,7 @@ export async function deployL1Contract(
|
|
|
1655
1683
|
l1TxUtils?: L1TxUtils;
|
|
1656
1684
|
gasLimit?: bigint;
|
|
1657
1685
|
acceleratedTestDeployments?: boolean;
|
|
1686
|
+
noSimulation?: boolean;
|
|
1658
1687
|
} = {},
|
|
1659
1688
|
): Promise<{
|
|
1660
1689
|
address: EthAddress;
|
|
@@ -1666,7 +1695,7 @@ export async function deployL1Contract(
|
|
|
1666
1695
|
let resultingAddress: Hex | null | undefined = undefined;
|
|
1667
1696
|
const deployedLibraries: VerificationLibraryEntry[] = [];
|
|
1668
1697
|
|
|
1669
|
-
const { salt: saltFromOpts, libraries, logger, gasLimit, acceleratedTestDeployments } = opts;
|
|
1698
|
+
const { salt: saltFromOpts, libraries, logger, gasLimit, acceleratedTestDeployments, noSimulation } = opts;
|
|
1670
1699
|
let { l1TxUtils } = opts;
|
|
1671
1700
|
|
|
1672
1701
|
if (!l1TxUtils) {
|
|
@@ -1775,11 +1804,13 @@ export async function deployL1Contract(
|
|
|
1775
1804
|
resultingAddress = address;
|
|
1776
1805
|
const existing = await extendedClient.getCode({ address: resultingAddress });
|
|
1777
1806
|
if (existing === undefined || existing === '0x') {
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1807
|
+
if (!noSimulation) {
|
|
1808
|
+
try {
|
|
1809
|
+
await l1TxUtils.simulate({ to: DEPLOYER_ADDRESS, data: concatHex([salt, calldata]), gas: gasLimit });
|
|
1810
|
+
} catch (err) {
|
|
1811
|
+
logger?.error(`Failed to simulate deployment tx using universal deployer`, err);
|
|
1812
|
+
await l1TxUtils.simulate({ to: null, data: encodeDeployData({ abi, bytecode, args }), gas: gasLimit });
|
|
1813
|
+
}
|
|
1783
1814
|
}
|
|
1784
1815
|
const res = await l1TxUtils.sendTransaction(
|
|
1785
1816
|
{ to: DEPLOYER_ADDRESS, data: concatHex([salt, calldata]) },
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
|
+
import type { Logger } from '@aztec/foundation/log';
|
|
4
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
5
|
+
import { DateProvider } from '@aztec/foundation/timer';
|
|
6
|
+
|
|
7
|
+
import { type Hex, extractChain } from 'viem';
|
|
8
|
+
import { anvil, mainnet, sepolia } from 'viem/chains';
|
|
9
|
+
|
|
10
|
+
import { L1Deployer } from './deploy_l1_contracts.js';
|
|
11
|
+
import type { ExtendedViemWalletClient } from './types.js';
|
|
12
|
+
|
|
13
|
+
export const FORWARDER_SOLIDITY_SOURCE = `
|
|
14
|
+
contract ForwarderProxy {
|
|
15
|
+
function forward(address target, bytes calldata data) external payable returns (bytes memory) {
|
|
16
|
+
(bool success, bytes memory result) = target.call{value: msg.value}(data);
|
|
17
|
+
require(success, "call failed");
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
}`;
|
|
21
|
+
|
|
22
|
+
export const FORWARDER_ABI = [
|
|
23
|
+
{
|
|
24
|
+
inputs: [
|
|
25
|
+
{
|
|
26
|
+
internalType: 'address',
|
|
27
|
+
name: 'target',
|
|
28
|
+
type: 'address',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
internalType: 'bytes',
|
|
32
|
+
name: 'data',
|
|
33
|
+
type: 'bytes',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
name: 'forward',
|
|
37
|
+
outputs: [
|
|
38
|
+
{
|
|
39
|
+
internalType: 'bytes',
|
|
40
|
+
name: '',
|
|
41
|
+
type: 'bytes',
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
stateMutability: 'payable',
|
|
45
|
+
type: 'function',
|
|
46
|
+
},
|
|
47
|
+
] as const;
|
|
48
|
+
|
|
49
|
+
export const FORWARDER_BYTECODE =
|
|
50
|
+
'0x6080604052348015600e575f5ffd5b506103bf8061001c5f395ff3fe60806040526004361061001d575f3560e01c80636fadcf7214610021575b5f5ffd5b61003b600480360381019061003691906101d0565b610051565b604051610048919061029d565b60405180910390f35b60605f5f8573ffffffffffffffffffffffffffffffffffffffff1634868660405161007d9291906102f9565b5f6040518083038185875af1925050503d805f81146100b7576040519150601f19603f3d011682016040523d82523d5f602084013e6100bc565b606091505b509150915081610101576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100f89061036b565b60405180910390fd5b80925050509392505050565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61013e82610115565b9050919050565b61014e81610134565b8114610158575f5ffd5b50565b5f8135905061016981610145565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f8401126101905761018f61016f565b5b8235905067ffffffffffffffff8111156101ad576101ac610173565b5b6020830191508360018202830111156101c9576101c8610177565b5b9250929050565b5f5f5f604084860312156101e7576101e661010d565b5b5f6101f48682870161015b565b935050602084013567ffffffffffffffff81111561021557610214610111565b5b6102218682870161017b565b92509250509250925092565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61026f8261022d565b6102798185610237565b9350610289818560208601610247565b61029281610255565b840191505092915050565b5f6020820190508181035f8301526102b58184610265565b905092915050565b5f81905092915050565b828183375f83830152505050565b5f6102e083856102bd565b93506102ed8385846102c7565b82840190509392505050565b5f6103058284866102d5565b91508190509392505050565b5f82825260208201905092915050565b7f63616c6c206661696c65640000000000000000000000000000000000000000005f82015250565b5f610355600b83610311565b915061036082610321565b602082019050919050565b5f6020820190508181035f83015261038281610349565b905091905056fea26469706673582212209a1c8cf638cf1569450a731ef9457b862f9e153b0a46e5555429bcf4dffd999564736f6c634300081e0033' as Hex;
|
|
51
|
+
|
|
52
|
+
const FORWARDER_ARTIFACT = {
|
|
53
|
+
name: 'Forwarder',
|
|
54
|
+
contractAbi: FORWARDER_ABI,
|
|
55
|
+
contractBytecode: FORWARDER_BYTECODE,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Deploys the forwarder proxy contract to L1.
|
|
60
|
+
* @param client - The L1 client to use for deployment
|
|
61
|
+
* @param logger - Optional logger
|
|
62
|
+
* @returns The deployed forwarder contract address
|
|
63
|
+
*/
|
|
64
|
+
export async function deployForwarderProxy(client: ExtendedViemWalletClient, logger?: Logger): Promise<EthAddress> {
|
|
65
|
+
const log = logger ?? createLogger('ethereum:forwarder');
|
|
66
|
+
const nonce = await client.getTransactionCount({ address: client.account.address });
|
|
67
|
+
const deployer = new L1Deployer(client, nonce, new DateProvider(), false, log, undefined, false);
|
|
68
|
+
|
|
69
|
+
log.info('Deploying forwarder proxy contract');
|
|
70
|
+
const deployment = await deployer.deploy(FORWARDER_ARTIFACT, []);
|
|
71
|
+
log.info(`Forwarder proxy deployed at ${deployment.address.toString()}`);
|
|
72
|
+
|
|
73
|
+
return deployment.address;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Main function for deploying the forwarder proxy from command line.
|
|
78
|
+
* Usage: node forwarder_proxy.js <private_key> <rpc_url>
|
|
79
|
+
*/
|
|
80
|
+
async function main() {
|
|
81
|
+
const args = process.argv.slice(2);
|
|
82
|
+
if (args.length < 3) {
|
|
83
|
+
console.error('Usage: node forwarder_proxy.js <private_key> <rpc_url> <chain_id>');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const [privateKey, rpcUrl, chainId] = args;
|
|
88
|
+
|
|
89
|
+
// Dynamic import to avoid pulling in dependencies at module load time
|
|
90
|
+
const { createExtendedL1Client } = await import('./client.js');
|
|
91
|
+
|
|
92
|
+
const client = createExtendedL1Client(
|
|
93
|
+
[rpcUrl],
|
|
94
|
+
privateKey.startsWith('0x') ? privateKey : `0x${privateKey}`,
|
|
95
|
+
extractChain({ chains: [mainnet, sepolia, anvil], id: parseInt(chainId) as any }),
|
|
96
|
+
);
|
|
97
|
+
const address = await deployForwarderProxy(client);
|
|
98
|
+
|
|
99
|
+
console.log(`Forwarder proxy deployed at: ${address.toString()}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Only run main if this is the entry point
|
|
103
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
104
|
+
main().catch(err => {
|
|
105
|
+
console.error('Failed to deploy forwarder proxy:', err);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
});
|
|
108
|
+
}
|
package/src/l1_reader.ts
CHANGED
|
@@ -6,6 +6,8 @@ import { type L1ContractAddresses, l1ContractAddressesMapping } from './l1_contr
|
|
|
6
6
|
export interface L1ReaderConfig {
|
|
7
7
|
/** List of URLs of Ethereum RPC nodes that services will connect to (comma separated). */
|
|
8
8
|
l1RpcUrls: string[];
|
|
9
|
+
/** The RPC Url of the ethereum debug host for trace and debug methods. */
|
|
10
|
+
l1DebugRpcUrls: string[];
|
|
9
11
|
/** The chain ID of the ethereum host. */
|
|
10
12
|
l1ChainId: number;
|
|
11
13
|
/** The deployed l1 contract addresses */
|
|
@@ -30,6 +32,12 @@ export const l1ReaderConfigMappings: ConfigMappingsType<L1ReaderConfig> = {
|
|
|
30
32
|
parseEnv: (val: string) => val.split(',').map(url => url.trim()),
|
|
31
33
|
defaultValue: [],
|
|
32
34
|
},
|
|
35
|
+
l1DebugRpcUrls: {
|
|
36
|
+
env: 'ETHEREUM_DEBUG_HOSTS',
|
|
37
|
+
description: 'The RPC Url of the ethereum debug host for trace and debug methods.',
|
|
38
|
+
parseEnv: (val: string) => val.split(',').map(url => url.trim()),
|
|
39
|
+
defaultValue: [],
|
|
40
|
+
},
|
|
33
41
|
viemPollingIntervalMS: {
|
|
34
42
|
env: 'L1_READER_VIEM_POLLING_INTERVAL_MS',
|
|
35
43
|
description: 'The polling interval viem uses in ms',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ConfigMappingsType,
|
|
3
|
-
bigintConfigHelper,
|
|
4
3
|
booleanConfigHelper,
|
|
4
|
+
floatConfigHelper,
|
|
5
5
|
getConfigFromMappings,
|
|
6
6
|
getDefaultConfig,
|
|
7
7
|
numberConfigHelper,
|
|
@@ -15,11 +15,11 @@ export interface L1TxUtilsConfig {
|
|
|
15
15
|
/**
|
|
16
16
|
* Maximum gas price in gwei
|
|
17
17
|
*/
|
|
18
|
-
maxGwei?:
|
|
18
|
+
maxGwei?: number;
|
|
19
19
|
/**
|
|
20
20
|
* Maximum blob fee per gas in gwei
|
|
21
21
|
*/
|
|
22
|
-
maxBlobGwei?:
|
|
22
|
+
maxBlobGwei?: number;
|
|
23
23
|
/**
|
|
24
24
|
* Priority fee bump percentage
|
|
25
25
|
*/
|
|
@@ -29,9 +29,9 @@ export interface L1TxUtilsConfig {
|
|
|
29
29
|
*/
|
|
30
30
|
priorityFeeRetryBumpPercentage?: number;
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
32
|
+
* Minimum priority fee per gas in Gwei. Acts as a floor for the computed priority fee.
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
minimumPriorityFeePerGas?: number;
|
|
35
35
|
/**
|
|
36
36
|
* Maximum number of speed-up attempts
|
|
37
37
|
*/
|
|
@@ -69,14 +69,16 @@ export const l1TxUtilsConfigMappings: ConfigMappingsType<L1TxUtilsConfig> = {
|
|
|
69
69
|
...numberConfigHelper(20),
|
|
70
70
|
},
|
|
71
71
|
maxGwei: {
|
|
72
|
-
description: 'Maximum gas price in gwei',
|
|
72
|
+
description: 'Maximum gas price in gwei to be used for transactions.',
|
|
73
73
|
env: 'L1_GAS_PRICE_MAX',
|
|
74
|
-
|
|
74
|
+
fallback: ['L1_FEE_PER_GAS_GWEI_MAX'],
|
|
75
|
+
...floatConfigHelper(2000),
|
|
75
76
|
},
|
|
76
77
|
maxBlobGwei: {
|
|
77
78
|
description: 'Maximum blob fee per gas in gwei',
|
|
78
79
|
env: 'L1_BLOB_FEE_PER_GAS_MAX',
|
|
79
|
-
|
|
80
|
+
fallback: ['L1_BLOB_FEE_PER_GAS_GWEI_MAX'],
|
|
81
|
+
...floatConfigHelper(3000),
|
|
80
82
|
},
|
|
81
83
|
priorityFeeBumpPercentage: {
|
|
82
84
|
description: 'How much to increase priority fee by each attempt (percentage)',
|
|
@@ -88,10 +90,22 @@ export const l1TxUtilsConfigMappings: ConfigMappingsType<L1TxUtilsConfig> = {
|
|
|
88
90
|
env: 'L1_PRIORITY_FEE_RETRY_BUMP_PERCENTAGE',
|
|
89
91
|
...numberConfigHelper(50),
|
|
90
92
|
},
|
|
91
|
-
|
|
92
|
-
description:
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
minimumPriorityFeePerGas: {
|
|
94
|
+
description:
|
|
95
|
+
'Minimum priority fee per gas in Gwei. Acts as a floor for the computed priority fee. If network conditions require a higher fee, the higher fee will be used.',
|
|
96
|
+
env: 'L1_MINIMUM_PRIORITY_FEE_PER_GAS_GWEI',
|
|
97
|
+
fallback: ['L1_FIXED_PRIORITY_FEE_PER_GAS', 'L1_FIXED_PRIORITY_FEE_PER_GAS_GWEI'],
|
|
98
|
+
deprecatedFallback: [
|
|
99
|
+
{
|
|
100
|
+
env: 'L1_FIXED_PRIORITY_FEE_PER_GAS',
|
|
101
|
+
message: deprecatedFixedFeeMessage('L1_FIXED_PRIORITY_FEE_PER_GAS'),
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
env: 'L1_FIXED_PRIORITY_FEE_PER_GAS_GWEI',
|
|
105
|
+
message: deprecatedFixedFeeMessage('L1_FIXED_PRIORITY_FEE_PER_GAS_GWEI'),
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
...floatConfigHelper(0),
|
|
95
109
|
},
|
|
96
110
|
maxSpeedUpAttempts: {
|
|
97
111
|
description: 'Maximum number of speed-up attempts',
|
|
@@ -106,7 +120,7 @@ export const l1TxUtilsConfigMappings: ConfigMappingsType<L1TxUtilsConfig> = {
|
|
|
106
120
|
stallTimeMs: {
|
|
107
121
|
description: 'How long before considering tx stalled',
|
|
108
122
|
env: 'L1_TX_MONITOR_STALL_TIME_MS',
|
|
109
|
-
...numberConfigHelper(
|
|
123
|
+
...numberConfigHelper(12_000), // 12s, 1 ethereum slot
|
|
110
124
|
},
|
|
111
125
|
txTimeoutMs: {
|
|
112
126
|
description: 'How long to wait for a tx to be mined before giving up. Set to 0 to disable.',
|
|
@@ -138,3 +152,10 @@ export const defaultL1TxUtilsConfig = getDefaultConfig<L1TxUtilsConfig>(
|
|
|
138
152
|
export function getL1TxUtilsConfigEnvVars(): L1TxUtilsConfig {
|
|
139
153
|
return getConfigFromMappings(l1TxUtilsConfigMappings);
|
|
140
154
|
}
|
|
155
|
+
|
|
156
|
+
function deprecatedFixedFeeMessage(envVar: string): string {
|
|
157
|
+
return (
|
|
158
|
+
`Environment variable ${envVar} is deprecated. It is now used as a MINIMUM priority fee rather than a fixed value. ` +
|
|
159
|
+
'Please use L1_MINIMUM_PRIORITY_FEE_PER_GAS_GWEI instead. If network conditions require a higher fee, the higher fee will be used.'
|
|
160
|
+
);
|
|
161
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
|
+
import type { Logger } from '@aztec/foundation/log';
|
|
3
|
+
import type { DateProvider } from '@aztec/foundation/timer';
|
|
4
|
+
|
|
5
|
+
import { type Hex, encodeFunctionData } from 'viem';
|
|
6
|
+
|
|
7
|
+
import type { EthSigner } from '../eth-signer/eth-signer.js';
|
|
8
|
+
import { FORWARDER_ABI } from '../forwarder_proxy.js';
|
|
9
|
+
import type { ExtendedViemWalletClient, ViemClient } from '../types.js';
|
|
10
|
+
import type { L1TxUtilsConfig } from './config.js';
|
|
11
|
+
import type { IL1TxMetrics, IL1TxStore } from './interfaces.js';
|
|
12
|
+
import { L1TxUtilsWithBlobs } from './l1_tx_utils_with_blobs.js';
|
|
13
|
+
import { createViemSigner } from './signer.js';
|
|
14
|
+
import type { L1BlobInputs, L1TxConfig, L1TxRequest, SigningCallback } from './types.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Extends L1TxUtilsWithBlobs to wrap all transactions through a forwarder contract.
|
|
18
|
+
* This is mainly used for testing the archiver's ability to decode transactions that go through proxies.
|
|
19
|
+
*/
|
|
20
|
+
export class ForwarderL1TxUtils extends L1TxUtilsWithBlobs {
|
|
21
|
+
constructor(
|
|
22
|
+
client: ViemClient | ExtendedViemWalletClient,
|
|
23
|
+
senderAddress: EthAddress,
|
|
24
|
+
signingCallback: SigningCallback,
|
|
25
|
+
logger: Logger | undefined,
|
|
26
|
+
dateProvider: DateProvider | undefined,
|
|
27
|
+
config: Partial<L1TxUtilsConfig>,
|
|
28
|
+
debugMaxGasLimit: boolean,
|
|
29
|
+
store: IL1TxStore | undefined,
|
|
30
|
+
metrics: IL1TxMetrics | undefined,
|
|
31
|
+
private readonly forwarderAddress: EthAddress,
|
|
32
|
+
) {
|
|
33
|
+
super(client, senderAddress, signingCallback, logger, dateProvider, config, debugMaxGasLimit, store, metrics);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Wraps the transaction request in a call to the forwarder contract.
|
|
38
|
+
*/
|
|
39
|
+
private wrapInForwarder(request: L1TxRequest): L1TxRequest {
|
|
40
|
+
const forwarderCalldata = encodeFunctionData({
|
|
41
|
+
abi: FORWARDER_ABI,
|
|
42
|
+
functionName: 'forward',
|
|
43
|
+
args: [request.to as Hex, request.data as Hex],
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
to: this.forwarderAddress.toString() as Hex,
|
|
48
|
+
data: forwarderCalldata,
|
|
49
|
+
value: request.value,
|
|
50
|
+
abi: request.abi, // Preserve the original ABI for error decoding
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Override sendAndMonitorTransaction to wrap the request in a forwarder call.
|
|
56
|
+
*/
|
|
57
|
+
public override sendAndMonitorTransaction(request: L1TxRequest, gasConfig?: L1TxConfig, blobInputs?: L1BlobInputs) {
|
|
58
|
+
this.logger.debug(`Wrapping transaction to ${request.to} in forwarder at ${this.forwarderAddress.toString()}`);
|
|
59
|
+
const wrappedRequest = this.wrapInForwarder(request);
|
|
60
|
+
return super.sendAndMonitorTransaction(wrappedRequest, gasConfig, blobInputs);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function createForwarderL1TxUtilsFromViemWallet(
|
|
65
|
+
client: ExtendedViemWalletClient,
|
|
66
|
+
forwarderAddress: EthAddress,
|
|
67
|
+
deps: {
|
|
68
|
+
logger?: Logger;
|
|
69
|
+
dateProvider?: DateProvider;
|
|
70
|
+
store?: IL1TxStore;
|
|
71
|
+
metrics?: IL1TxMetrics;
|
|
72
|
+
} = {},
|
|
73
|
+
config: Partial<L1TxUtilsConfig> = {},
|
|
74
|
+
debugMaxGasLimit: boolean = false,
|
|
75
|
+
) {
|
|
76
|
+
return new ForwarderL1TxUtils(
|
|
77
|
+
client,
|
|
78
|
+
EthAddress.fromString(client.account.address),
|
|
79
|
+
createViemSigner(client),
|
|
80
|
+
deps.logger,
|
|
81
|
+
deps.dateProvider,
|
|
82
|
+
config,
|
|
83
|
+
debugMaxGasLimit,
|
|
84
|
+
deps.store,
|
|
85
|
+
deps.metrics,
|
|
86
|
+
forwarderAddress,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function createForwarderL1TxUtilsFromEthSigner(
|
|
91
|
+
client: ViemClient,
|
|
92
|
+
signer: EthSigner,
|
|
93
|
+
forwarderAddress: EthAddress,
|
|
94
|
+
deps: {
|
|
95
|
+
logger?: Logger;
|
|
96
|
+
dateProvider?: DateProvider;
|
|
97
|
+
store?: IL1TxStore;
|
|
98
|
+
metrics?: IL1TxMetrics;
|
|
99
|
+
} = {},
|
|
100
|
+
config: Partial<L1TxUtilsConfig> = {},
|
|
101
|
+
debugMaxGasLimit: boolean = false,
|
|
102
|
+
) {
|
|
103
|
+
const callback: SigningCallback = async (transaction, _signingAddress) => {
|
|
104
|
+
return (await signer.signTransaction(transaction)).toViemTransactionSignature();
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
return new ForwarderL1TxUtils(
|
|
108
|
+
client,
|
|
109
|
+
signer.address,
|
|
110
|
+
callback,
|
|
111
|
+
deps.logger,
|
|
112
|
+
deps.dateProvider,
|
|
113
|
+
config,
|
|
114
|
+
debugMaxGasLimit,
|
|
115
|
+
deps.store,
|
|
116
|
+
deps.metrics,
|
|
117
|
+
forwarderAddress,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
@@ -46,7 +46,7 @@ export interface IL1TxStore {
|
|
|
46
46
|
* @param account - The sender account address
|
|
47
47
|
* @param stateId - The state ID to delete
|
|
48
48
|
*/
|
|
49
|
-
deleteState(account: string, stateId: number): Promise<void>;
|
|
49
|
+
deleteState(account: string, ...stateId: number[]): Promise<void>;
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Clears all transaction states for a specific account.
|
|
@@ -130,12 +130,32 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
// Clean up excess states if we have more than MAX_L1_TX_STATES
|
|
134
|
+
if (loadedStates.length > MAX_L1_TX_STATES) {
|
|
135
|
+
this.logger.warn(
|
|
136
|
+
`Found ${loadedStates.length} tx states for account ${account}, pruning to most recent ${MAX_L1_TX_STATES}`,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
// Keep only the most recent MAX_L1_TX_STATES
|
|
140
|
+
const statesToKeep = loadedStates.slice(-MAX_L1_TX_STATES);
|
|
141
|
+
const statesToDelete = loadedStates.slice(0, -MAX_L1_TX_STATES);
|
|
142
|
+
|
|
143
|
+
// Batch delete old states in a transaction for efficiency
|
|
144
|
+
const idsToDelete = statesToDelete.map(s => s.id);
|
|
145
|
+
await this.store.deleteState(account, ...idsToDelete);
|
|
146
|
+
|
|
147
|
+
this.txs = statesToKeep;
|
|
148
|
+
this.logger.info(
|
|
149
|
+
`Cleaned up ${statesToDelete.length} old tx states, kept ${statesToKeep.length} for account ${account}`,
|
|
150
|
+
);
|
|
151
|
+
} else {
|
|
152
|
+
// Convert loaded states (which have id) to the txs format
|
|
153
|
+
this.txs = loadedStates;
|
|
154
|
+
this.logger.info(`Rehydrated ${loadedStates.length} tx states for account ${account}`);
|
|
155
|
+
}
|
|
136
156
|
|
|
137
157
|
// Find all pending states and resume monitoring
|
|
138
|
-
const pendingStates =
|
|
158
|
+
const pendingStates = this.txs.filter(state => !TerminalTxUtilsState.includes(state.status));
|
|
139
159
|
if (pendingStates.length === 0) {
|
|
140
160
|
return;
|
|
141
161
|
}
|