@aztec/ethereum 0.0.1-commit.f2ce05ee → 0.0.1-commit.f5d02921e
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/client.d.ts +10 -2
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +13 -7
- package/dest/config.d.ts +3 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +10 -2
- package/dest/contracts/empire_base.d.ts +3 -1
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.d.ts +3 -1
- package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.js +9 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts +101 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
- package/dest/contracts/fee_asset_price_oracle.js +651 -0
- package/dest/contracts/governance.js +3 -3
- package/dest/contracts/governance_proposer.d.ts +3 -1
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +9 -0
- package/dest/contracts/index.d.ts +2 -1
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +1 -0
- package/dest/contracts/multicall.d.ts +51 -2
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +85 -0
- package/dest/contracts/registry.d.ts +3 -1
- package/dest/contracts/registry.d.ts.map +1 -1
- package/dest/contracts/registry.js +30 -1
- package/dest/contracts/rollup.d.ts +45 -9
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +209 -17
- package/dest/deploy_aztec_l1_contracts.d.ts +2 -3
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +33 -19
- package/dest/deploy_l1_contract.js +3 -3
- package/dest/generated/l1-contracts-defaults.d.ts +1 -1
- package/dest/generated/l1-contracts-defaults.js +1 -1
- package/dest/l1_artifacts.d.ts +1051 -42
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_reader.d.ts +3 -1
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +6 -1
- package/dest/l1_tx_utils/config.d.ts +7 -1
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +14 -1
- package/dest/l1_tx_utils/factory.d.ts +18 -10
- package/dest/l1_tx_utils/factory.d.ts.map +1 -1
- package/dest/l1_tx_utils/factory.js +17 -7
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +1 -1
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +1 -1
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +15 -15
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +9 -15
- package/dest/l1_tx_utils/index-blobs.d.ts +3 -3
- package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -1
- package/dest/l1_tx_utils/index-blobs.js +2 -2
- package/dest/l1_tx_utils/index.d.ts +2 -1
- package/dest/l1_tx_utils/index.d.ts.map +1 -1
- package/dest/l1_tx_utils/index.js +1 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +20 -7
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +74 -50
- 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/readonly_l1_tx_utils.js +8 -4
- package/dest/l1_tx_utils/tx_delayer.d.ts +56 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
- package/dest/{test → l1_tx_utils}/tx_delayer.js +62 -34
- package/dest/publisher_manager.d.ts +21 -7
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +81 -7
- package/dest/test/chain_monitor.d.ts +22 -3
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +33 -2
- package/dest/test/eth_cheat_codes.d.ts +6 -4
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +6 -4
- package/dest/test/index.d.ts +1 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +0 -2
- package/dest/test/start_anvil.d.ts +23 -3
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +143 -29
- package/dest/test/upgrade_utils.js +2 -2
- package/dest/utils.d.ts +1 -1
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +16 -12
- package/package.json +5 -7
- package/src/client.ts +10 -2
- package/src/config.ts +14 -1
- package/src/contracts/empire_base.ts +2 -0
- package/src/contracts/empire_slashing_proposer.ts +6 -0
- package/src/contracts/fee_asset_price_oracle.ts +280 -0
- package/src/contracts/governance.ts +3 -3
- package/src/contracts/governance_proposer.ts +6 -0
- package/src/contracts/index.ts +1 -0
- package/src/contracts/multicall.ts +65 -1
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +244 -29
- package/src/deploy_aztec_l1_contracts.ts +56 -29
- package/src/deploy_l1_contract.ts +3 -3
- package/src/generated/l1-contracts-defaults.ts +1 -1
- package/src/l1_reader.ts +13 -1
- package/src/l1_tx_utils/config.ts +20 -0
- package/src/l1_tx_utils/factory.ts +31 -31
- package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +1 -1
- package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +1 -1
- package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +43 -54
- package/src/l1_tx_utils/index-blobs.ts +2 -2
- package/src/l1_tx_utils/index.ts +1 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +67 -29
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +8 -4
- package/src/{test → l1_tx_utils}/tx_delayer.ts +78 -50
- package/src/publisher_manager.ts +105 -10
- package/src/test/chain_monitor.ts +60 -3
- package/src/test/eth_cheat_codes.ts +6 -4
- package/src/test/index.ts +0 -2
- package/src/test/start_anvil.ts +177 -29
- package/src/test/upgrade_utils.ts +2 -2
- package/src/utils.ts +17 -14
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +0 -26
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +0 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +0 -26
- package/dest/test/delayed_tx_utils.d.ts +0 -13
- package/dest/test/delayed_tx_utils.d.ts.map +0 -1
- package/dest/test/delayed_tx_utils.js +0 -28
- package/dest/test/tx_delayer.d.ts +0 -36
- package/dest/test/tx_delayer.d.ts.map +0 -1
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
- package/src/test/delayed_tx_utils.ts +0 -52
package/src/contracts/rollup.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
4
4
|
import { memoize } from '@aztec/foundation/decorators';
|
|
5
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
6
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
7
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
7
8
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
8
9
|
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
9
10
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
type Hex,
|
|
17
18
|
type StateOverride,
|
|
18
19
|
type WatchContractEventReturnType,
|
|
20
|
+
encodeAbiParameters,
|
|
19
21
|
encodeFunctionData,
|
|
20
22
|
getContract,
|
|
21
23
|
hexToBigInt,
|
|
@@ -134,6 +136,14 @@ export type L1FeeData = {
|
|
|
134
136
|
blobFee: bigint;
|
|
135
137
|
};
|
|
136
138
|
|
|
139
|
+
/** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
|
|
140
|
+
export type ManaMinFeeComponents = {
|
|
141
|
+
sequencerCost: bigint;
|
|
142
|
+
proverCost: bigint;
|
|
143
|
+
congestionCost: bigint;
|
|
144
|
+
congestionMultiplier: bigint;
|
|
145
|
+
};
|
|
146
|
+
|
|
137
147
|
/**
|
|
138
148
|
* Reward configuration for the rollup
|
|
139
149
|
*/
|
|
@@ -193,10 +203,10 @@ export type CheckpointProposedArgs = {
|
|
|
193
203
|
checkpointNumber: CheckpointNumber;
|
|
194
204
|
archive: Fr;
|
|
195
205
|
versionedBlobHashes: Buffer[];
|
|
196
|
-
/** Hash of attestations
|
|
197
|
-
attestationsHash
|
|
198
|
-
/** Digest of the payload
|
|
199
|
-
payloadDigest
|
|
206
|
+
/** Hash of attestations emitted in the CheckpointProposed event. */
|
|
207
|
+
attestationsHash: Buffer32;
|
|
208
|
+
/** Digest of the payload emitted in the CheckpointProposed event. */
|
|
209
|
+
payloadDigest: Buffer32;
|
|
200
210
|
};
|
|
201
211
|
|
|
202
212
|
/** Log type for CheckpointProposed events. */
|
|
@@ -204,6 +214,7 @@ export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
|
204
214
|
|
|
205
215
|
export class RollupContract {
|
|
206
216
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
217
|
+
private readonly logger = createLogger('ethereum:rollup');
|
|
207
218
|
|
|
208
219
|
private static cachedStfStorageSlot: Hex | undefined;
|
|
209
220
|
private cachedEscapeHatch?: {
|
|
@@ -379,6 +390,20 @@ export class RollupContract {
|
|
|
379
390
|
return Fr.fromString(await this.rollup.read.archiveAt([0n]));
|
|
380
391
|
}
|
|
381
392
|
|
|
393
|
+
@memoize
|
|
394
|
+
async getVkTreeRoot(): Promise<Fr> {
|
|
395
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 3n;
|
|
396
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
397
|
+
return Fr.fromString(value ?? '0x0');
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
@memoize
|
|
401
|
+
async getProtocolContractsHash(): Promise<Fr> {
|
|
402
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 4n;
|
|
403
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
404
|
+
return Fr.fromString(value ?? '0x0');
|
|
405
|
+
}
|
|
406
|
+
|
|
382
407
|
/**
|
|
383
408
|
* Returns rollup constants used for epoch queries.
|
|
384
409
|
* Return type is `L1RollupConstants` which is defined in stdlib,
|
|
@@ -392,16 +417,25 @@ export class RollupContract {
|
|
|
392
417
|
epochDuration: number;
|
|
393
418
|
proofSubmissionEpochs: number;
|
|
394
419
|
targetCommitteeSize: number;
|
|
420
|
+
rollupManaLimit: number;
|
|
395
421
|
}> {
|
|
396
|
-
const [
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
422
|
+
const [
|
|
423
|
+
l1StartBlock,
|
|
424
|
+
l1GenesisTime,
|
|
425
|
+
slotDuration,
|
|
426
|
+
epochDuration,
|
|
427
|
+
proofSubmissionEpochs,
|
|
428
|
+
targetCommitteeSize,
|
|
429
|
+
rollupManaLimit,
|
|
430
|
+
] = await Promise.all([
|
|
431
|
+
this.getL1StartBlock(),
|
|
432
|
+
this.getL1GenesisTime(),
|
|
433
|
+
this.getSlotDuration(),
|
|
434
|
+
this.getEpochDuration(),
|
|
435
|
+
this.getProofSubmissionEpochs(),
|
|
436
|
+
this.getTargetCommitteeSize(),
|
|
437
|
+
this.getManaLimit(),
|
|
438
|
+
]);
|
|
405
439
|
return {
|
|
406
440
|
l1StartBlock,
|
|
407
441
|
l1GenesisTime,
|
|
@@ -409,6 +443,7 @@ export class RollupContract {
|
|
|
409
443
|
epochDuration: Number(epochDuration),
|
|
410
444
|
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
411
445
|
targetCommitteeSize,
|
|
446
|
+
rollupManaLimit: Number(rollupManaLimit),
|
|
412
447
|
};
|
|
413
448
|
}
|
|
414
449
|
|
|
@@ -463,7 +498,11 @@ export class RollupContract {
|
|
|
463
498
|
|
|
464
499
|
const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
|
|
465
500
|
return isOpen;
|
|
466
|
-
} catch {
|
|
501
|
+
} catch (err) {
|
|
502
|
+
this.logger.warn('isEscapeHatchOpen failed (treating as closed); RPC or contract error may cause liveness risk', {
|
|
503
|
+
epoch: Number(epoch),
|
|
504
|
+
error: err,
|
|
505
|
+
});
|
|
467
506
|
return false;
|
|
468
507
|
}
|
|
469
508
|
}
|
|
@@ -503,8 +542,9 @@ export class RollupContract {
|
|
|
503
542
|
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber());
|
|
504
543
|
}
|
|
505
544
|
|
|
506
|
-
async getProvenCheckpointNumber(): Promise<CheckpointNumber> {
|
|
507
|
-
|
|
545
|
+
async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
546
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
547
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
508
548
|
}
|
|
509
549
|
|
|
510
550
|
async getSlotNumber(): Promise<SlotNumber> {
|
|
@@ -745,16 +785,23 @@ export class RollupContract {
|
|
|
745
785
|
* timestamp of the next L1 block
|
|
746
786
|
* @throws otherwise
|
|
747
787
|
*/
|
|
748
|
-
public async
|
|
788
|
+
public async canProposeAt(
|
|
749
789
|
archive: Buffer,
|
|
750
790
|
account: `0x${string}` | Account,
|
|
751
|
-
|
|
752
|
-
opts: {
|
|
791
|
+
timestamp: bigint,
|
|
792
|
+
opts: {
|
|
793
|
+
forcePendingCheckpointNumber?: CheckpointNumber;
|
|
794
|
+
forceArchive?: { checkpointNumber: CheckpointNumber; archive: Fr };
|
|
795
|
+
} = {},
|
|
753
796
|
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
754
|
-
const
|
|
755
|
-
const timeOfNextL1Slot = latestBlock.timestamp + BigInt(slotDuration);
|
|
797
|
+
const timeOfNextL1Slot = timestamp;
|
|
756
798
|
const who = typeof account === 'string' ? account : account.address;
|
|
757
799
|
|
|
800
|
+
const stateOverride = RollupContract.mergeStateOverrides(
|
|
801
|
+
await this.makePendingCheckpointNumberOverride(opts.forcePendingCheckpointNumber),
|
|
802
|
+
opts.forceArchive ? this.makeArchiveOverride(opts.forceArchive.checkpointNumber, opts.forceArchive.archive) : [],
|
|
803
|
+
);
|
|
804
|
+
|
|
758
805
|
try {
|
|
759
806
|
const {
|
|
760
807
|
result: [slot, checkpointNumber],
|
|
@@ -764,7 +811,7 @@ export class RollupContract {
|
|
|
764
811
|
functionName: 'canProposeAtTime',
|
|
765
812
|
args: [timeOfNextL1Slot, `0x${archive.toString('hex')}`, who],
|
|
766
813
|
account,
|
|
767
|
-
stateOverride
|
|
814
|
+
stateOverride,
|
|
768
815
|
});
|
|
769
816
|
|
|
770
817
|
return {
|
|
@@ -800,6 +847,151 @@ export class RollupContract {
|
|
|
800
847
|
];
|
|
801
848
|
}
|
|
802
849
|
|
|
850
|
+
/**
|
|
851
|
+
* Returns a state override that sets tempCheckpointLogs[checkpointNumber].feeHeader to the compressed fee header.
|
|
852
|
+
* Used when simulating a propose call where the parent checkpoint hasn't landed on L1 yet (pipelining).
|
|
853
|
+
*/
|
|
854
|
+
public async makeFeeHeaderOverride(checkpointNumber: CheckpointNumber, feeHeader: FeeHeader): Promise<StateOverride> {
|
|
855
|
+
const { epochDuration, proofSubmissionEpochs } = await this.getRollupConstants();
|
|
856
|
+
const roundaboutSize = BigInt(epochDuration * (proofSubmissionEpochs + 1) + 1);
|
|
857
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
858
|
+
|
|
859
|
+
// tempCheckpointLogs is at offset 2 in RollupStore
|
|
860
|
+
const tempCheckpointLogsMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 2n;
|
|
861
|
+
|
|
862
|
+
// Solidity mapping slot: keccak256(abi.encode(key, baseSlot))
|
|
863
|
+
const structBaseSlot = hexToBigInt(
|
|
864
|
+
keccak256(
|
|
865
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsMappingBase]),
|
|
866
|
+
),
|
|
867
|
+
);
|
|
868
|
+
|
|
869
|
+
// feeHeader is the 7th field (offset 6) in CompressedTempCheckpointLog
|
|
870
|
+
const feeHeaderSlot = structBaseSlot + 6n;
|
|
871
|
+
const compressed = RollupContract.compressFeeHeader(feeHeader);
|
|
872
|
+
|
|
873
|
+
return [
|
|
874
|
+
{
|
|
875
|
+
address: this.address,
|
|
876
|
+
stateDiff: [
|
|
877
|
+
{
|
|
878
|
+
slot: `0x${feeHeaderSlot.toString(16).padStart(64, '0')}`,
|
|
879
|
+
value: `0x${compressed.toString(16).padStart(64, '0')}`,
|
|
880
|
+
},
|
|
881
|
+
],
|
|
882
|
+
},
|
|
883
|
+
];
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Returns a state override that sets archives[checkpointNumber] to the given archive value.
|
|
888
|
+
* Used when simulating a canProposeAtTime call where the local archive differs from L1
|
|
889
|
+
* (e.g. pipelining where the parent checkpoint hasn't landed on L1 yet).
|
|
890
|
+
*/
|
|
891
|
+
public makeArchiveOverride(checkpointNumber: CheckpointNumber, archive: Fr): StateOverride {
|
|
892
|
+
const archivesMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 1n;
|
|
893
|
+
const archiveSlot = hexToBigInt(
|
|
894
|
+
keccak256(
|
|
895
|
+
encodeAbiParameters(
|
|
896
|
+
[{ type: 'uint256' }, { type: 'uint256' }],
|
|
897
|
+
[BigInt(checkpointNumber), archivesMappingBase],
|
|
898
|
+
),
|
|
899
|
+
),
|
|
900
|
+
);
|
|
901
|
+
return [
|
|
902
|
+
{
|
|
903
|
+
address: this.address,
|
|
904
|
+
stateDiff: [
|
|
905
|
+
{
|
|
906
|
+
slot: `0x${archiveSlot.toString(16).padStart(64, '0')}`,
|
|
907
|
+
value: archive.toString(),
|
|
908
|
+
},
|
|
909
|
+
],
|
|
910
|
+
},
|
|
911
|
+
];
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/** Merges multiple StateOverride arrays, combining stateDiff entries for the same address. */
|
|
915
|
+
public static mergeStateOverrides(...overrides: StateOverride[]): StateOverride {
|
|
916
|
+
type StateDiffEntry = { slot: `0x${string}`; value: `0x${string}` };
|
|
917
|
+
const byAddress = new Map<string, { address: `0x${string}`; balance?: bigint; stateDiff: StateDiffEntry[] }>();
|
|
918
|
+
for (const override of overrides) {
|
|
919
|
+
for (const entry of override) {
|
|
920
|
+
const key = entry.address.toLowerCase();
|
|
921
|
+
const existing = byAddress.get(key);
|
|
922
|
+
if (existing) {
|
|
923
|
+
existing.stateDiff.push(...(entry.stateDiff ?? []));
|
|
924
|
+
if (entry.balance !== undefined) {
|
|
925
|
+
existing.balance = entry.balance;
|
|
926
|
+
}
|
|
927
|
+
} else {
|
|
928
|
+
byAddress.set(key, {
|
|
929
|
+
address: entry.address,
|
|
930
|
+
balance: entry.balance,
|
|
931
|
+
stateDiff: [...(entry.stateDiff ?? [])],
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
return [...byAddress.values()];
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/** Compresses a FeeHeader into a uint256 matching FeeHeaderLib.compress() in FeeStructs.sol. */
|
|
940
|
+
public static compressFeeHeader(feeHeader: FeeHeader): bigint {
|
|
941
|
+
const MASK_48_BITS = (1n << 48n) - 1n;
|
|
942
|
+
const MASK_64_BITS = (1n << 64n) - 1n;
|
|
943
|
+
const MASK_63_BITS = (1n << 63n) - 1n;
|
|
944
|
+
|
|
945
|
+
let value = BigInt(feeHeader.manaUsed) & ((1n << 32n) - 1n); // bits [0:31]
|
|
946
|
+
value |= (feeHeader.excessMana < MASK_48_BITS ? feeHeader.excessMana : MASK_48_BITS) << 32n; // bits [32:79]
|
|
947
|
+
value |= (BigInt(feeHeader.ethPerFeeAsset) & MASK_48_BITS) << 80n; // bits [80:127]
|
|
948
|
+
value |= (feeHeader.congestionCost < MASK_64_BITS ? feeHeader.congestionCost : MASK_64_BITS) << 128n; // bits [128:191]
|
|
949
|
+
value |= (feeHeader.proverCost < MASK_63_BITS ? feeHeader.proverCost : MASK_63_BITS) << 192n; // bits [192:254]
|
|
950
|
+
value |= 1n << 255n; // preheat flag
|
|
951
|
+
return value;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/** Computes the fee header for a child checkpoint given parent fee header and child data.
|
|
955
|
+
* Must stay in sync with Solidity FeeLib.sol (computeNewEthPerFeeAsset, clampedAdd). */
|
|
956
|
+
public static computeChildFeeHeader(
|
|
957
|
+
parentFeeHeader: FeeHeader,
|
|
958
|
+
childManaUsed: bigint,
|
|
959
|
+
feeAssetPriceModifier: bigint,
|
|
960
|
+
manaTarget: bigint,
|
|
961
|
+
): FeeHeader {
|
|
962
|
+
const MIN_ETH_PER_FEE_ASSET = 100n;
|
|
963
|
+
const MAX_ETH_PER_FEE_ASSET = 100_000_000_000_000n; // 1e14, matches FeeLib.sol
|
|
964
|
+
|
|
965
|
+
// excessMana = clampedAdd(parent.excessMana + parent.manaUsed, -manaTarget)
|
|
966
|
+
const sum = parentFeeHeader.excessMana + parentFeeHeader.manaUsed;
|
|
967
|
+
const excessMana = sum > manaTarget ? sum - manaTarget : 0n;
|
|
968
|
+
|
|
969
|
+
// ethPerFeeAsset = computeNewEthPerFeeAsset(max(parent.ethPerFeeAsset, MIN), modifier)
|
|
970
|
+
const parentPrice =
|
|
971
|
+
parentFeeHeader.ethPerFeeAsset > MIN_ETH_PER_FEE_ASSET ? parentFeeHeader.ethPerFeeAsset : MIN_ETH_PER_FEE_ASSET;
|
|
972
|
+
let newPrice: bigint;
|
|
973
|
+
if (feeAssetPriceModifier >= 0n) {
|
|
974
|
+
newPrice = (parentPrice * (10_000n + feeAssetPriceModifier)) / 10_000n;
|
|
975
|
+
} else {
|
|
976
|
+
const absMod = -feeAssetPriceModifier;
|
|
977
|
+
newPrice = (parentPrice * (10_000n - absMod)) / 10_000n;
|
|
978
|
+
}
|
|
979
|
+
if (newPrice < MIN_ETH_PER_FEE_ASSET) {
|
|
980
|
+
newPrice = MIN_ETH_PER_FEE_ASSET;
|
|
981
|
+
}
|
|
982
|
+
if (newPrice > MAX_ETH_PER_FEE_ASSET) {
|
|
983
|
+
newPrice = MAX_ETH_PER_FEE_ASSET;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
return {
|
|
987
|
+
excessMana,
|
|
988
|
+
manaUsed: childManaUsed,
|
|
989
|
+
ethPerFeeAsset: newPrice,
|
|
990
|
+
congestionCost: 0n,
|
|
991
|
+
proverCost: 0n,
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
|
|
803
995
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
804
996
|
public buildInvalidateBadAttestationRequest(
|
|
805
997
|
checkpointNumber: CheckpointNumber,
|
|
@@ -848,8 +1040,18 @@ export class RollupContract {
|
|
|
848
1040
|
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]);
|
|
849
1041
|
}
|
|
850
1042
|
|
|
851
|
-
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean): Promise<bigint> {
|
|
852
|
-
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset]);
|
|
1043
|
+
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean, stateOverride?: StateOverride): Promise<bigint> {
|
|
1044
|
+
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset], { stateOverride });
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
async getManaMinFeeComponentsAt(timestamp: bigint, inFeeAsset: boolean): Promise<ManaMinFeeComponents> {
|
|
1048
|
+
const result = await this.rollup.read.getManaMinFeeComponentsAt([timestamp, inFeeAsset]);
|
|
1049
|
+
return {
|
|
1050
|
+
sequencerCost: result.sequencerCost,
|
|
1051
|
+
proverCost: result.proverCost,
|
|
1052
|
+
congestionCost: result.congestionCost,
|
|
1053
|
+
congestionMultiplier: result.congestionMultiplier,
|
|
1054
|
+
};
|
|
853
1055
|
}
|
|
854
1056
|
|
|
855
1057
|
async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
|
|
@@ -895,11 +1097,10 @@ export class RollupContract {
|
|
|
895
1097
|
return this.rollup.read.getSpecificProverRewardsForEpoch([epoch, prover]);
|
|
896
1098
|
}
|
|
897
1099
|
|
|
898
|
-
async getAttesters(): Promise<EthAddress[]> {
|
|
1100
|
+
async getAttesters(timestamp?: bigint): Promise<EthAddress[]> {
|
|
899
1101
|
const attesterSize = await this.getActiveAttesterCount();
|
|
900
1102
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
901
|
-
const ts = (await this.client.getBlock()).timestamp;
|
|
902
|
-
|
|
1103
|
+
const ts = timestamp ?? (await this.client.getBlock()).timestamp;
|
|
903
1104
|
const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i));
|
|
904
1105
|
const chunks = chunk(indices, 1000);
|
|
905
1106
|
|
|
@@ -1060,8 +1261,22 @@ export class RollupContract {
|
|
|
1060
1261
|
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
1061
1262
|
archive: Fr.fromString(log.args.archive!),
|
|
1062
1263
|
versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
|
|
1063
|
-
attestationsHash:
|
|
1064
|
-
|
|
1264
|
+
attestationsHash: (() => {
|
|
1265
|
+
if (!log.args.attestationsHash) {
|
|
1266
|
+
throw new Error(
|
|
1267
|
+
`CheckpointProposed event missing attestationsHash for checkpoint ${log.args.checkpointNumber}`,
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
return Buffer32.fromString(log.args.attestationsHash);
|
|
1271
|
+
})(),
|
|
1272
|
+
payloadDigest: (() => {
|
|
1273
|
+
if (!log.args.payloadDigest) {
|
|
1274
|
+
throw new Error(
|
|
1275
|
+
`CheckpointProposed event missing payloadDigest for checkpoint ${log.args.checkpointNumber}`,
|
|
1276
|
+
);
|
|
1277
|
+
}
|
|
1278
|
+
return Buffer32.fromString(log.args.payloadDigest);
|
|
1279
|
+
})(),
|
|
1065
1280
|
},
|
|
1066
1281
|
}));
|
|
1067
1282
|
}
|
|
@@ -23,7 +23,6 @@ import type { L1ContractsConfig } from './config.js';
|
|
|
23
23
|
import { deployMulticall3 } from './contracts/multicall.js';
|
|
24
24
|
import { RollupContract } from './contracts/rollup.js';
|
|
25
25
|
import type { L1ContractAddresses } from './l1_contract_addresses.js';
|
|
26
|
-
import type { L1TxUtilsConfig } from './l1_tx_utils/config.js';
|
|
27
26
|
import type { ExtendedViemWalletClient } from './types.js';
|
|
28
27
|
|
|
29
28
|
const logger = createLogger('ethereum:deploy_aztec_l1_contracts');
|
|
@@ -31,9 +30,9 @@ const logger = createLogger('ethereum:deploy_aztec_l1_contracts');
|
|
|
31
30
|
const JSON_DEPLOY_RESULT_PREFIX = 'JSON DEPLOY RESULT:';
|
|
32
31
|
|
|
33
32
|
/**
|
|
34
|
-
* Runs a process
|
|
35
|
-
*
|
|
36
|
-
*
|
|
33
|
+
* Runs a process and parses JSON deploy results from stdout.
|
|
34
|
+
* Lines starting with JSON_DEPLOY_RESULT_PREFIX are parsed and returned.
|
|
35
|
+
* All other stdout goes to logger.info, stderr goes to logger.warn.
|
|
37
36
|
*/
|
|
38
37
|
function runProcess<T>(
|
|
39
38
|
command: string,
|
|
@@ -49,26 +48,41 @@ function runProcess<T>(
|
|
|
49
48
|
});
|
|
50
49
|
|
|
51
50
|
let result: T | undefined;
|
|
51
|
+
let parseError: Error | undefined;
|
|
52
|
+
let settled = false;
|
|
52
53
|
|
|
53
54
|
readline.createInterface({ input: proc.stdout }).on('line', line => {
|
|
54
55
|
const trimmedLine = line.trim();
|
|
55
56
|
if (trimmedLine.startsWith(JSON_DEPLOY_RESULT_PREFIX)) {
|
|
56
57
|
const jsonStr = trimmedLine.slice(JSON_DEPLOY_RESULT_PREFIX.length).trim();
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
try {
|
|
59
|
+
result = JSON.parse(jsonStr);
|
|
60
|
+
} catch {
|
|
61
|
+
parseError = new Error(`Failed to parse deploy result JSON: ${jsonStr.slice(0, 200)}`);
|
|
62
|
+
}
|
|
59
63
|
} else {
|
|
60
64
|
logger.info(line);
|
|
61
65
|
}
|
|
62
66
|
});
|
|
63
|
-
readline.createInterface({ input: proc.stderr }).on('line', logger.
|
|
67
|
+
readline.createInterface({ input: proc.stderr }).on('line', logger.warn.bind(logger));
|
|
64
68
|
|
|
65
69
|
proc.on('error', error => {
|
|
70
|
+
if (settled) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
settled = true;
|
|
66
74
|
reject(new Error(`Failed to spawn ${command}: ${error.message}`));
|
|
67
75
|
});
|
|
68
76
|
|
|
69
77
|
proc.on('close', code => {
|
|
78
|
+
if (settled) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
settled = true;
|
|
70
82
|
if (code !== 0) {
|
|
71
|
-
reject(new Error(`${command} exited with code ${code}
|
|
83
|
+
reject(new Error(`${command} exited with code ${code}`));
|
|
84
|
+
} else if (parseError) {
|
|
85
|
+
reject(parseError);
|
|
72
86
|
} else {
|
|
73
87
|
resolve(result);
|
|
74
88
|
}
|
|
@@ -321,11 +335,8 @@ export async function deployAztecL1Contracts(
|
|
|
321
335
|
);
|
|
322
336
|
}
|
|
323
337
|
|
|
324
|
-
|
|
325
|
-
const MAGIC_ANVIL_BATCH_SIZE = 8;
|
|
326
|
-
// Anvil seems to stall with unbounded batch size. Otherwise no max batch size is desirable.
|
|
338
|
+
const scriptPath = join(getL1ContractsPath(), 'scripts', 'forge_broadcast.js');
|
|
327
339
|
const forgeArgs = [
|
|
328
|
-
'script',
|
|
329
340
|
FORGE_SCRIPT,
|
|
330
341
|
'--sig',
|
|
331
342
|
'run()',
|
|
@@ -333,9 +344,6 @@ export async function deployAztecL1Contracts(
|
|
|
333
344
|
privateKey,
|
|
334
345
|
'--rpc-url',
|
|
335
346
|
rpcUrl,
|
|
336
|
-
'--broadcast',
|
|
337
|
-
'--batch-size',
|
|
338
|
-
MAGIC_ANVIL_BATCH_SIZE.toString(),
|
|
339
347
|
...(shouldVerify ? ['--verify'] : []),
|
|
340
348
|
];
|
|
341
349
|
const forgeEnv = {
|
|
@@ -344,7 +352,12 @@ export async function deployAztecL1Contracts(
|
|
|
344
352
|
FOUNDRY_PROFILE: chainId === mainnet.id ? 'production' : undefined,
|
|
345
353
|
...getDeployAztecL1ContractsEnvVars(args),
|
|
346
354
|
};
|
|
347
|
-
const result = await runProcess<ForgeL1ContractsDeployResult>(
|
|
355
|
+
const result = await runProcess<ForgeL1ContractsDeployResult>(
|
|
356
|
+
process.execPath,
|
|
357
|
+
[scriptPath, ...forgeArgs],
|
|
358
|
+
forgeEnv,
|
|
359
|
+
l1ContractsPath,
|
|
360
|
+
);
|
|
348
361
|
if (!result) {
|
|
349
362
|
throw new Error('Forge script did not output deployment result');
|
|
350
363
|
}
|
|
@@ -477,7 +490,25 @@ export type VerificationRecord = {
|
|
|
477
490
|
libraries: VerificationLibraryEntry[];
|
|
478
491
|
};
|
|
479
492
|
|
|
480
|
-
export interface DeployAztecL1ContractsArgs
|
|
493
|
+
export interface DeployAztecL1ContractsArgs
|
|
494
|
+
extends Omit<
|
|
495
|
+
L1ContractsConfig,
|
|
496
|
+
| 'gasLimitBufferPercentage'
|
|
497
|
+
| 'maxGwei'
|
|
498
|
+
| 'maxBlobGwei'
|
|
499
|
+
| 'priorityFeeBumpPercentage'
|
|
500
|
+
| 'priorityFeeRetryBumpPercentage'
|
|
501
|
+
| 'minimumPriorityFeePerGas'
|
|
502
|
+
| 'maxSpeedUpAttempts'
|
|
503
|
+
| 'checkIntervalMs'
|
|
504
|
+
| 'stallTimeMs'
|
|
505
|
+
| 'txTimeoutMs'
|
|
506
|
+
| 'cancelTxOnTimeout'
|
|
507
|
+
| 'txCancellationFinalTimeoutMs'
|
|
508
|
+
| 'txUnseenConsideredDroppedMs'
|
|
509
|
+
| 'enableDelayer'
|
|
510
|
+
| 'txDelayerMaxInclusionTimeIntoSlot'
|
|
511
|
+
> {
|
|
481
512
|
/** The vk tree root. */
|
|
482
513
|
vkTreeRoot: Fr;
|
|
483
514
|
/** The hash of the protocol contracts. */
|
|
@@ -587,17 +618,8 @@ export const deployRollupForUpgrade = async (
|
|
|
587
618
|
const FORGE_SCRIPT = 'script/deploy/DeployRollupForUpgrade.s.sol';
|
|
588
619
|
await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
589
620
|
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
FORGE_SCRIPT,
|
|
593
|
-
'--sig',
|
|
594
|
-
'run()',
|
|
595
|
-
'--private-key',
|
|
596
|
-
privateKey,
|
|
597
|
-
'--rpc-url',
|
|
598
|
-
rpcUrl,
|
|
599
|
-
'--broadcast',
|
|
600
|
-
];
|
|
621
|
+
const scriptPath = join(getL1ContractsPath(), 'scripts', 'forge_broadcast.js');
|
|
622
|
+
const forgeArgs = [FORGE_SCRIPT, '--sig', 'run()', '--private-key', privateKey, '--rpc-url', rpcUrl];
|
|
601
623
|
const forgeEnv = {
|
|
602
624
|
FOUNDRY_PROFILE: chainId === mainnet.id ? 'production' : undefined,
|
|
603
625
|
// Env vars required by l1-contracts/script/deploy/RollupConfiguration.sol.
|
|
@@ -606,7 +628,12 @@ export const deployRollupForUpgrade = async (
|
|
|
606
628
|
...getDeployRollupForUpgradeEnvVars(args),
|
|
607
629
|
};
|
|
608
630
|
|
|
609
|
-
const result = await runProcess<ForgeRollupUpgradeResult>(
|
|
631
|
+
const result = await runProcess<ForgeRollupUpgradeResult>(
|
|
632
|
+
process.execPath,
|
|
633
|
+
[scriptPath, ...forgeArgs],
|
|
634
|
+
forgeEnv,
|
|
635
|
+
l1ContractsPath,
|
|
636
|
+
);
|
|
610
637
|
if (!result) {
|
|
611
638
|
throw new Error('Forge script did not output deployment result');
|
|
612
639
|
}
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
} from './deploy_aztec_l1_contracts.js';
|
|
25
25
|
import { RegisterNewRollupVersionPayloadArtifact } from './l1_artifacts.js';
|
|
26
26
|
import { type L1TxUtilsConfig, getL1TxUtilsConfigEnvVars } from './l1_tx_utils/config.js';
|
|
27
|
-
import {
|
|
27
|
+
import { createL1TxUtils } from './l1_tx_utils/factory.js';
|
|
28
28
|
import type { L1TxUtils } from './l1_tx_utils/l1_tx_utils.js';
|
|
29
29
|
import type { GasPrice, L1TxConfig, L1TxRequest } from './l1_tx_utils/types.js';
|
|
30
30
|
import type { ExtendedViemWalletClient } from './types.js';
|
|
@@ -46,7 +46,7 @@ export class L1Deployer {
|
|
|
46
46
|
private createVerificationJson: boolean = false,
|
|
47
47
|
) {
|
|
48
48
|
this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), { size: 32 }) : undefined;
|
|
49
|
-
this.l1TxUtils =
|
|
49
|
+
this.l1TxUtils = createL1TxUtils(
|
|
50
50
|
this.client,
|
|
51
51
|
{ logger: this.logger, dateProvider },
|
|
52
52
|
{ ...this.txUtilsConfig, debugMaxGasLimit: acceleratedTestDeployments },
|
|
@@ -179,7 +179,7 @@ export async function deployL1Contract(
|
|
|
179
179
|
|
|
180
180
|
if (!l1TxUtils) {
|
|
181
181
|
const config = getL1TxUtilsConfigEnvVars();
|
|
182
|
-
l1TxUtils =
|
|
182
|
+
l1TxUtils = createL1TxUtils(
|
|
183
183
|
extendedClient,
|
|
184
184
|
{ logger },
|
|
185
185
|
{ ...config, debugMaxGasLimit: acceleratedTestDeployments },
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/** Default L1 contracts configuration values from network-defaults.yml */
|
|
5
5
|
export const l1ContractsDefaultEnv = {
|
|
6
6
|
ETHEREUM_SLOT_DURATION: 12,
|
|
7
|
-
AZTEC_SLOT_DURATION:
|
|
7
|
+
AZTEC_SLOT_DURATION: 72,
|
|
8
8
|
AZTEC_EPOCH_DURATION: 32,
|
|
9
9
|
AZTEC_TARGET_COMMITTEE_SIZE: 48,
|
|
10
10
|
AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET: 2,
|
package/src/l1_reader.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ConfigMappingsType,
|
|
3
|
+
getConfigFromMappings,
|
|
4
|
+
numberConfigHelper,
|
|
5
|
+
optionalNumberConfigHelper,
|
|
6
|
+
} from '@aztec/foundation/config';
|
|
2
7
|
|
|
3
8
|
import { type L1ContractAddresses, l1ContractAddressesMapping } from './l1_contract_addresses.js';
|
|
4
9
|
|
|
@@ -14,6 +19,8 @@ export interface L1ReaderConfig {
|
|
|
14
19
|
l1Contracts: L1ContractAddresses;
|
|
15
20
|
/** The polling interval viem uses in ms */
|
|
16
21
|
viemPollingIntervalMS: number;
|
|
22
|
+
/** Timeout for HTTP requests to the L1 RPC node in ms. */
|
|
23
|
+
l1HttpTimeoutMS?: number;
|
|
17
24
|
}
|
|
18
25
|
|
|
19
26
|
export const l1ReaderConfigMappings: ConfigMappingsType<L1ReaderConfig> = {
|
|
@@ -43,6 +50,11 @@ export const l1ReaderConfigMappings: ConfigMappingsType<L1ReaderConfig> = {
|
|
|
43
50
|
description: 'The polling interval viem uses in ms',
|
|
44
51
|
...numberConfigHelper(1_000),
|
|
45
52
|
},
|
|
53
|
+
l1HttpTimeoutMS: {
|
|
54
|
+
env: 'ETHEREUM_HTTP_TIMEOUT_MS',
|
|
55
|
+
description: 'Timeout for HTTP requests to the L1 RPC node in ms.',
|
|
56
|
+
...optionalNumberConfigHelper(),
|
|
57
|
+
},
|
|
46
58
|
};
|
|
47
59
|
|
|
48
60
|
export function getL1ReaderConfigFromEnv(): L1ReaderConfig {
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
getConfigFromMappings,
|
|
6
6
|
getDefaultConfig,
|
|
7
7
|
numberConfigHelper,
|
|
8
|
+
optionalNumberConfigHelper,
|
|
8
9
|
} from '@aztec/foundation/config';
|
|
9
10
|
|
|
10
11
|
export interface L1TxUtilsConfig {
|
|
@@ -60,6 +61,12 @@ export interface L1TxUtilsConfig {
|
|
|
60
61
|
* How long a tx nonce can be unseen in the mempool before considering it dropped
|
|
61
62
|
*/
|
|
62
63
|
txUnseenConsideredDroppedMs?: number;
|
|
64
|
+
/** Enable tx delayer. When true, wraps the viem client to intercept and delay txs. Test-only. */
|
|
65
|
+
enableDelayer?: boolean;
|
|
66
|
+
/** Max seconds into an L1 slot for tx inclusion. Txs sent later are deferred to next slot. Only used when enableDelayer is true. */
|
|
67
|
+
txDelayerMaxInclusionTimeIntoSlot?: number;
|
|
68
|
+
/** How many seconds an L1 slot lasts. */
|
|
69
|
+
ethereumSlotDuration?: number;
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
export const l1TxUtilsConfigMappings: ConfigMappingsType<L1TxUtilsConfig> = {
|
|
@@ -142,6 +149,19 @@ export const l1TxUtilsConfigMappings: ConfigMappingsType<L1TxUtilsConfig> = {
|
|
|
142
149
|
env: 'L1_TX_MONITOR_TX_UNSEEN_CONSIDERED_DROPPED_MS',
|
|
143
150
|
...numberConfigHelper(6 * 12 * 1000), // 6 L1 blocks
|
|
144
151
|
},
|
|
152
|
+
enableDelayer: {
|
|
153
|
+
description: 'Enable tx delayer for testing.',
|
|
154
|
+
...booleanConfigHelper(false),
|
|
155
|
+
},
|
|
156
|
+
txDelayerMaxInclusionTimeIntoSlot: {
|
|
157
|
+
description: 'Max seconds into L1 slot for tx inclusion when delayer is enabled.',
|
|
158
|
+
...optionalNumberConfigHelper(),
|
|
159
|
+
},
|
|
160
|
+
ethereumSlotDuration: {
|
|
161
|
+
env: 'ETHEREUM_SLOT_DURATION',
|
|
162
|
+
description: 'How many seconds an L1 slot lasts.',
|
|
163
|
+
...numberConfigHelper(12),
|
|
164
|
+
},
|
|
145
165
|
};
|
|
146
166
|
|
|
147
167
|
// We abuse the fact that all mappings above have a non null default value and force-type this to Required
|