@aztec/ethereum 0.0.1-commit.9ef841308 → 0.0.1-commit.a4600f49
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 +17 -3
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +49 -3
- package/dest/config.d.ts +27 -8
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +59 -12
- package/dest/contracts/chain_state_override.d.ts +78 -0
- package/dest/contracts/chain_state_override.d.ts.map +1 -0
- package/dest/contracts/chain_state_override.js +137 -0
- package/dest/contracts/empire_base.d.ts +1 -3
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/fee_asset_price_oracle.d.ts +6 -2
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -1
- package/dest/contracts/fee_asset_price_oracle.js +11 -6
- package/dest/contracts/governance.d.ts +108 -33
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +193 -12
- package/dest/contracts/governance_proposer.d.ts +33 -3
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +51 -9
- package/dest/contracts/gse.d.ts +4 -2
- package/dest/contracts/gse.d.ts.map +1 -1
- package/dest/contracts/gse.js +2 -2
- package/dest/contracts/inbox.d.ts +3 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +12 -7
- package/dest/contracts/index.d.ts +3 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +2 -2
- package/dest/contracts/multicall.d.ts +82 -14
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +119 -95
- package/dest/contracts/outbox.d.ts +27 -4
- package/dest/contracts/outbox.d.ts.map +1 -1
- package/dest/contracts/outbox.js +34 -7
- package/dest/contracts/rollup.d.ts +5399 -25
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +333 -64
- package/dest/contracts/{tally_slashing_proposer.d.ts → slashing_proposer.d.ts} +3 -4
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/{tally_slashing_proposer.js → slashing_proposer.js} +13 -15
- package/dest/deploy_aztec_l1_contracts.d.ts +18 -10
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +17 -13
- package/dest/l1_artifacts.d.ts +14941 -16273
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +9 -24
- package/dest/l1_contract_addresses.d.ts +61 -65
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +101 -82
- package/dest/l1_reader.d.ts +3 -5
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +3 -6
- package/dest/l1_tx_utils/config.js +3 -3
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +23 -4
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_fee_analyzer.js +65 -3
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +7 -1
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +106 -33
- 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 +2 -1
- package/dest/l1_tx_utils/tx_delayer.d.ts +5 -3
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -1
- package/dest/l1_tx_utils/tx_delayer.js +7 -5
- package/dest/l1_tx_utils/types.d.ts +27 -1
- package/dest/l1_tx_utils/types.d.ts.map +1 -1
- package/dest/l1_tx_utils/types.js +10 -0
- package/dest/publisher_manager.d.ts +18 -6
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +44 -7
- package/dest/queries.d.ts +13 -2
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +69 -4
- package/dest/test/blob_kzg_warmup.d.ts +19 -0
- package/dest/test/blob_kzg_warmup.d.ts.map +1 -0
- package/dest/test/blob_kzg_warmup.js +64 -0
- package/dest/test/chain_monitor.d.ts +34 -2
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +76 -6
- package/dest/test/eth_cheat_codes.d.ts +32 -3
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +83 -37
- package/dest/test/index.d.ts +2 -1
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +1 -0
- package/dest/test/rollup_cheat_codes.d.ts +60 -3
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +86 -7
- package/dest/utils.d.ts +9 -2
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +34 -6
- package/package.json +6 -7
- package/src/client.ts +57 -1
- package/src/config.ts +82 -16
- package/src/contracts/chain_state_override.ts +200 -0
- package/src/contracts/empire_base.ts +0 -2
- package/src/contracts/fee_asset_price_oracle.ts +10 -5
- package/src/contracts/governance.ts +266 -9
- package/src/contracts/governance_proposer.ts +52 -5
- package/src/contracts/gse.ts +7 -2
- package/src/contracts/inbox.ts +13 -5
- package/src/contracts/index.ts +2 -2
- package/src/contracts/multicall.ts +183 -106
- package/src/contracts/outbox.ts +42 -8
- package/src/contracts/rollup.ts +372 -62
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +14 -16
- package/src/deploy_aztec_l1_contracts.ts +16 -14
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +120 -94
- package/src/l1_reader.ts +4 -9
- package/src/l1_tx_utils/config.ts +3 -3
- package/src/l1_tx_utils/l1_fee_analyzer.ts +75 -3
- package/src/l1_tx_utils/l1_tx_utils.ts +99 -35
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +2 -1
- package/src/l1_tx_utils/tx_delayer.ts +16 -7
- package/src/l1_tx_utils/types.ts +32 -0
- package/src/publisher_manager.ts +54 -18
- package/src/queries.ts +76 -4
- package/src/test/blob_kzg_warmup.ts +65 -0
- package/src/test/chain_monitor.ts +93 -5
- package/src/test/eth_cheat_codes.ts +76 -41
- package/src/test/index.ts +1 -0
- package/src/test/rollup_cheat_codes.ts +115 -6
- package/src/utils.ts +30 -6
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -69
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -216
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- package/dest/generated/l1-contracts-defaults.d.ts +0 -30
- package/dest/generated/l1-contracts-defaults.d.ts.map +0 -1
- package/dest/generated/l1-contracts-defaults.js +0 -30
- package/src/contracts/empire_slashing_proposer.ts +0 -265
- package/src/generated/l1-contracts-defaults.ts +0 -32
package/src/contracts/rollup.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
6
6
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
7
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
8
8
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
9
|
+
import { getErrorCause } from '@aztec/foundation/types';
|
|
9
10
|
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
10
11
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
11
12
|
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
@@ -13,10 +14,15 @@ import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
|
13
14
|
import chunk from 'lodash.chunk';
|
|
14
15
|
import {
|
|
15
16
|
type Account,
|
|
17
|
+
ContractFunctionRevertedError,
|
|
16
18
|
type GetContractReturnType,
|
|
17
19
|
type Hex,
|
|
20
|
+
type Log,
|
|
21
|
+
RpcRequestError,
|
|
18
22
|
type StateOverride,
|
|
19
23
|
type WatchContractEventReturnType,
|
|
24
|
+
decodeErrorResult,
|
|
25
|
+
encodeAbiParameters,
|
|
20
26
|
encodeFunctionData,
|
|
21
27
|
getContract,
|
|
22
28
|
hexToBigInt,
|
|
@@ -30,11 +36,10 @@ import type { L1ReaderConfig } from '../l1_reader.js';
|
|
|
30
36
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
31
37
|
import type { ViemClient } from '../types.js';
|
|
32
38
|
import { formatViemError } from '../utils.js';
|
|
33
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
34
39
|
import { GSEContract } from './gse.js';
|
|
35
40
|
import type { L1EventLog } from './log.js';
|
|
36
41
|
import { SlasherContract } from './slasher_contract.js';
|
|
37
|
-
import {
|
|
42
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
38
43
|
import { checkBlockTag } from './utils.js';
|
|
39
44
|
|
|
40
45
|
export type ViemCommitteeAttestation = {
|
|
@@ -56,7 +61,6 @@ export type L1RollupContractAddresses = Pick<
|
|
|
56
61
|
| 'feeJuiceAddress'
|
|
57
62
|
| 'stakingAssetAddress'
|
|
58
63
|
| 'rewardDistributorAddress'
|
|
59
|
-
| 'slashFactoryAddress'
|
|
60
64
|
| 'gseAddress'
|
|
61
65
|
>;
|
|
62
66
|
|
|
@@ -79,6 +83,7 @@ export type ViemHeader = {
|
|
|
79
83
|
feeRecipient: `0x${string}`;
|
|
80
84
|
gasFees: ViemGasFees;
|
|
81
85
|
totalManaUsed: bigint;
|
|
86
|
+
accumulatedFees: bigint;
|
|
82
87
|
};
|
|
83
88
|
|
|
84
89
|
export type ViemGasFees = {
|
|
@@ -86,12 +91,6 @@ export type ViemGasFees = {
|
|
|
86
91
|
feePerL2Gas: bigint;
|
|
87
92
|
};
|
|
88
93
|
|
|
89
|
-
export enum SlashingProposerType {
|
|
90
|
-
None = 0,
|
|
91
|
-
Tally = 1,
|
|
92
|
-
Empire = 2,
|
|
93
|
-
}
|
|
94
|
-
|
|
95
94
|
/**
|
|
96
95
|
* Status of a validator/attester in the staking system.
|
|
97
96
|
* Matches the Status enum in StakingLib.sol
|
|
@@ -135,6 +134,31 @@ export type L1FeeData = {
|
|
|
135
134
|
blobFee: bigint;
|
|
136
135
|
};
|
|
137
136
|
|
|
137
|
+
/** Field offsets within the CompressedTempCheckpointLog struct in Solidity storage. */
|
|
138
|
+
export enum TempCheckpointLogField {
|
|
139
|
+
HeaderHash = 0,
|
|
140
|
+
BlobCommitmentsHash = 1,
|
|
141
|
+
OutHash = 2,
|
|
142
|
+
AttestationsHash = 3,
|
|
143
|
+
PayloadDigest = 4,
|
|
144
|
+
SlotNumber = 5,
|
|
145
|
+
FeeHeader = 6,
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Field-level override input for `tempCheckpointLogs[checkpointNumber]`. Covers the fields the
|
|
150
|
+
* `propose()` path actually reads back. `payloadDigest` is `Buffer32` because it carries an
|
|
151
|
+
* arbitrary `bytes32` value rather than a BN254 scalar. `slotNumber` carries the uint32 portion
|
|
152
|
+
* of the on-chain `CompressedSlot`.
|
|
153
|
+
*/
|
|
154
|
+
export type TempCheckpointLogOverrideFields = {
|
|
155
|
+
headerHash?: Fr;
|
|
156
|
+
outHash?: Fr;
|
|
157
|
+
payloadDigest?: Buffer32;
|
|
158
|
+
slotNumber?: SlotNumber;
|
|
159
|
+
feeHeader?: FeeHeader;
|
|
160
|
+
};
|
|
161
|
+
|
|
138
162
|
/** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
|
|
139
163
|
export type ManaMinFeeComponents = {
|
|
140
164
|
sequencerCost: bigint;
|
|
@@ -211,6 +235,32 @@ export type CheckpointProposedArgs = {
|
|
|
211
235
|
/** Log type for CheckpointProposed events. */
|
|
212
236
|
export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
213
237
|
|
|
238
|
+
const INSUFFICIENT_VALIDATOR_SET_SIZE_ERROR = 'ValidatorSelection__InsufficientValidatorSetSize';
|
|
239
|
+
|
|
240
|
+
function isValidatorSelectionError(err: unknown, errorName: string): boolean {
|
|
241
|
+
return (
|
|
242
|
+
getErrorCause(err, ContractFunctionRevertedError)?.data?.errorName === errorName ||
|
|
243
|
+
decodeRpcRequestErrorName(err) === errorName
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function decodeRpcRequestErrorName(err: unknown): string | undefined {
|
|
248
|
+
const data = getErrorCause(err, RpcRequestError)?.data;
|
|
249
|
+
if (!isHexString(data)) {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
return decodeErrorResult({ abi: RollupAbi, data }).errorName;
|
|
255
|
+
} catch {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function isHexString(value: unknown): value is Hex {
|
|
261
|
+
return typeof value === 'string' && value.startsWith('0x');
|
|
262
|
+
}
|
|
263
|
+
|
|
214
264
|
export class RollupContract {
|
|
215
265
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
216
266
|
private readonly logger = createLogger('ethereum:rollup');
|
|
@@ -243,7 +293,7 @@ export class RollupContract {
|
|
|
243
293
|
|
|
244
294
|
static getFromConfig(config: L1ReaderConfig) {
|
|
245
295
|
const client = getPublicClient(config);
|
|
246
|
-
const address = config.
|
|
296
|
+
const address = config.rollupAddress.toString();
|
|
247
297
|
return new RollupContract(client, address);
|
|
248
298
|
}
|
|
249
299
|
|
|
@@ -269,34 +319,18 @@ export class RollupContract {
|
|
|
269
319
|
return this.rollup;
|
|
270
320
|
}
|
|
271
321
|
|
|
272
|
-
public async getSlashingProposer(): Promise<
|
|
273
|
-
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
274
|
-
> {
|
|
322
|
+
public async getSlashingProposer(): Promise<SlashingProposerContract | undefined> {
|
|
275
323
|
const slasher = await this.getSlasherContract();
|
|
276
324
|
if (!slasher) {
|
|
277
325
|
return undefined;
|
|
278
326
|
}
|
|
279
327
|
|
|
280
328
|
const proposerAddress = await slasher.getProposer();
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
type: 'function',
|
|
284
|
-
name: 'SLASHING_PROPOSER_TYPE',
|
|
285
|
-
inputs: [],
|
|
286
|
-
outputs: [{ name: '', type: 'uint8', internalType: 'enum SlasherFlavor' }],
|
|
287
|
-
stateMutability: 'view',
|
|
288
|
-
},
|
|
289
|
-
] as const;
|
|
290
|
-
|
|
291
|
-
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
|
|
292
|
-
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
293
|
-
if (proposerType === SlashingProposerType.Tally.valueOf()) {
|
|
294
|
-
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
295
|
-
} else if (proposerType === SlashingProposerType.Empire.valueOf()) {
|
|
296
|
-
return new EmpireSlashingProposerContract(this.client, proposerAddress);
|
|
297
|
-
} else {
|
|
298
|
-
throw new Error(`Unknown slashing proposer type: ${proposerType}`);
|
|
329
|
+
if (proposerAddress.isZero()) {
|
|
330
|
+
return undefined;
|
|
299
331
|
}
|
|
332
|
+
|
|
333
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
300
334
|
}
|
|
301
335
|
|
|
302
336
|
@memoize
|
|
@@ -521,8 +555,9 @@ export class RollupContract {
|
|
|
521
555
|
return EthAddress.fromString(await this.rollup.read.owner());
|
|
522
556
|
}
|
|
523
557
|
|
|
524
|
-
async getActiveAttesterCount(): Promise<number> {
|
|
525
|
-
|
|
558
|
+
async getActiveAttesterCount(options?: { blockNumber?: bigint }): Promise<number> {
|
|
559
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
560
|
+
return Number(await this.rollup.read.getActiveAttesterCount(options));
|
|
526
561
|
}
|
|
527
562
|
|
|
528
563
|
public async getSlashingProposerAddress() {
|
|
@@ -537,8 +572,9 @@ export class RollupContract {
|
|
|
537
572
|
return this.rollup.read.getCheckpointReward();
|
|
538
573
|
}
|
|
539
574
|
|
|
540
|
-
async getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
541
|
-
|
|
575
|
+
async getCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
576
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
577
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber(options));
|
|
542
578
|
}
|
|
543
579
|
|
|
544
580
|
async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
@@ -546,18 +582,31 @@ export class RollupContract {
|
|
|
546
582
|
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
547
583
|
}
|
|
548
584
|
|
|
549
|
-
async getSlotNumber(): Promise<SlotNumber> {
|
|
550
|
-
|
|
585
|
+
async getSlotNumber(options?: { blockNumber?: bigint }): Promise<SlotNumber> {
|
|
586
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
587
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot(options));
|
|
551
588
|
}
|
|
552
589
|
|
|
553
|
-
async getL1FeesAt(timestamp: bigint): Promise<L1FeeData> {
|
|
554
|
-
|
|
590
|
+
async getL1FeesAt(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<L1FeeData> {
|
|
591
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
592
|
+
const result = await this.rollup.read.getL1FeesAt([timestamp], options);
|
|
555
593
|
return {
|
|
556
594
|
baseFee: result.baseFee,
|
|
557
595
|
blobFee: result.blobFee,
|
|
558
596
|
};
|
|
559
597
|
}
|
|
560
598
|
|
|
599
|
+
async getFeeHeader(checkpointNumber: bigint): Promise<FeeHeader> {
|
|
600
|
+
const result = await this.rollup.read.getFeeHeader([checkpointNumber]);
|
|
601
|
+
return {
|
|
602
|
+
excessMana: result.excessMana,
|
|
603
|
+
manaUsed: result.manaUsed,
|
|
604
|
+
ethPerFeeAsset: result.ethPerFeeAsset,
|
|
605
|
+
congestionCost: result.congestionCost,
|
|
606
|
+
proverCost: result.proverCost,
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
561
610
|
getEthPerFeeAsset(): Promise<bigint> {
|
|
562
611
|
return this.rollup.read.getEthPerFeeAsset();
|
|
563
612
|
}
|
|
@@ -571,7 +620,7 @@ export class RollupContract {
|
|
|
571
620
|
args: [timestamp],
|
|
572
621
|
})
|
|
573
622
|
.catch(e => {
|
|
574
|
-
if (e
|
|
623
|
+
if (isValidatorSelectionError(e, INSUFFICIENT_VALIDATOR_SET_SIZE_ERROR)) {
|
|
575
624
|
return { result: undefined };
|
|
576
625
|
}
|
|
577
626
|
throw e;
|
|
@@ -601,7 +650,7 @@ export class RollupContract {
|
|
|
601
650
|
args: [],
|
|
602
651
|
})
|
|
603
652
|
.catch(e => {
|
|
604
|
-
if (e
|
|
653
|
+
if (isValidatorSelectionError(e, INSUFFICIENT_VALIDATOR_SET_SIZE_ERROR)) {
|
|
605
654
|
return { result: undefined };
|
|
606
655
|
}
|
|
607
656
|
throw e;
|
|
@@ -632,8 +681,9 @@ export class RollupContract {
|
|
|
632
681
|
return EthAddress.fromString(result);
|
|
633
682
|
}
|
|
634
683
|
|
|
635
|
-
async getCheckpoint(checkpointNumber: CheckpointNumber): Promise<CheckpointLog> {
|
|
636
|
-
|
|
684
|
+
async getCheckpoint(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise<CheckpointLog> {
|
|
685
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
686
|
+
const result = await this.rollup.read.getCheckpoint([BigInt(checkpointNumber)], options);
|
|
637
687
|
return {
|
|
638
688
|
archive: Fr.fromString(result.archive),
|
|
639
689
|
headerHash: Buffer32.fromString(result.headerHash),
|
|
@@ -666,6 +716,30 @@ export class RollupContract {
|
|
|
666
716
|
);
|
|
667
717
|
}
|
|
668
718
|
|
|
719
|
+
/**
|
|
720
|
+
* Returns the effective pending checkpoint, accounting for potential prunes.
|
|
721
|
+
* When a prune can happen, the L1 contract uses the proven checkpoint instead of the pending one.
|
|
722
|
+
* This mirrors the behavior of getEffectivePendingCheckpointNumber in STFLib.sol.
|
|
723
|
+
* @param atTimestamp - The timestamp to evaluate pruneability at. Defaults to the current L1 block timestamp.
|
|
724
|
+
* @param options - Optional L1 block number to pin the queries to.
|
|
725
|
+
*/
|
|
726
|
+
getEffectivePendingCheckpoint(atTimestamp?: bigint, options?: { blockNumber?: bigint }) {
|
|
727
|
+
return retry(
|
|
728
|
+
async () => {
|
|
729
|
+
const timestamp = atTimestamp ?? (await this.client.getBlock()).timestamp;
|
|
730
|
+
const canPrune = await this.canPruneAtTime(timestamp, options);
|
|
731
|
+
if (canPrune) {
|
|
732
|
+
const provenCheckpointNumber = await this.getProvenCheckpointNumber(options);
|
|
733
|
+
return await this.getCheckpoint(provenCheckpointNumber, options);
|
|
734
|
+
}
|
|
735
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber(options);
|
|
736
|
+
return await this.getCheckpoint(pendingCheckpointNumber, options);
|
|
737
|
+
},
|
|
738
|
+
'getting effective pending checkpoint',
|
|
739
|
+
makeBackoff([0.5, 0.5, 0.5]),
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
|
|
669
743
|
async getTips(): Promise<{ pending: CheckpointNumber; proven: CheckpointNumber }> {
|
|
670
744
|
const { pending, proven } = await this.rollup.read.getTips();
|
|
671
745
|
return {
|
|
@@ -740,7 +814,7 @@ export class RollupContract {
|
|
|
740
814
|
}
|
|
741
815
|
|
|
742
816
|
async getEpochProofPublicInputs(
|
|
743
|
-
args: readonly [bigint, bigint, EpochProofPublicInputArgs, readonly
|
|
817
|
+
args: readonly [bigint, bigint, EpochProofPublicInputArgs, readonly ViemHeader[], `0x${string}`],
|
|
744
818
|
): Promise<Fr[]> {
|
|
745
819
|
const result = await this.rollup.read.getEpochProofPublicInputs(args);
|
|
746
820
|
return result.map(Fr.fromString);
|
|
@@ -788,7 +862,7 @@ export class RollupContract {
|
|
|
788
862
|
archive: Buffer,
|
|
789
863
|
account: `0x${string}` | Account,
|
|
790
864
|
timestamp: bigint,
|
|
791
|
-
|
|
865
|
+
stateOverride: StateOverride = [],
|
|
792
866
|
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
793
867
|
const timeOfNextL1Slot = timestamp;
|
|
794
868
|
const who = typeof account === 'string' ? account : account.address;
|
|
@@ -802,7 +876,7 @@ export class RollupContract {
|
|
|
802
876
|
functionName: 'canProposeAtTime',
|
|
803
877
|
args: [timeOfNextL1Slot, `0x${archive.toString('hex')}`, who],
|
|
804
878
|
account,
|
|
805
|
-
stateOverride
|
|
879
|
+
stateOverride,
|
|
806
880
|
});
|
|
807
881
|
|
|
808
882
|
return {
|
|
@@ -816,20 +890,32 @@ export class RollupContract {
|
|
|
816
890
|
}
|
|
817
891
|
|
|
818
892
|
/**
|
|
819
|
-
* Returns a state override that sets the pending
|
|
820
|
-
*
|
|
821
|
-
*
|
|
893
|
+
* Returns a state override that sets the pending and/or proven checkpoint numbers. Useful for simulations.
|
|
894
|
+
* Both values share a single storage slot (pending in the upper 128 bits, proven in the lower 128 bits), so
|
|
895
|
+
* a single combined override is emitted to avoid the second state-diff clobbering the first. The current live
|
|
896
|
+
* value is read once to preserve any half not being overridden. Returns an empty override if neither is set.
|
|
897
|
+
*
|
|
898
|
+
* Throws if the resulting `proven > pending`, which would crash the simulation: `STFLib.canPruneAtTime` calls
|
|
899
|
+
* `getEpochForCheckpoint(proven + 1)` whenever `pending != proven`, and that asserts `_n <= tips.pending`.
|
|
822
900
|
*/
|
|
823
|
-
public async
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
901
|
+
public async makeChainTipsOverride(override: {
|
|
902
|
+
pending?: CheckpointNumber;
|
|
903
|
+
proven?: CheckpointNumber;
|
|
904
|
+
}): Promise<StateOverride> {
|
|
905
|
+
if (override.pending === undefined && override.proven === undefined) {
|
|
827
906
|
return [];
|
|
828
907
|
}
|
|
829
908
|
const slot = RollupContract.stfStorageSlot;
|
|
830
909
|
const currentValue = await this.client.getStorageAt({ address: this.address, slot });
|
|
831
|
-
const
|
|
832
|
-
const
|
|
910
|
+
const currentRaw = currentValue ? hexToBigInt(currentValue) : 0n;
|
|
911
|
+
const currentPending = currentRaw >> 128n;
|
|
912
|
+
const currentProven = currentRaw & ((1n << 128n) - 1n);
|
|
913
|
+
const newPending = override.pending !== undefined ? BigInt(override.pending) : currentPending;
|
|
914
|
+
const newProven = override.proven !== undefined ? BigInt(override.proven) : currentProven;
|
|
915
|
+
if (newProven > newPending) {
|
|
916
|
+
throw new Error(`Invalid chain tips override: proven (${newProven}) > pending (${newPending})`);
|
|
917
|
+
}
|
|
918
|
+
const newValue = (newPending << 128n) | newProven;
|
|
833
919
|
return [
|
|
834
920
|
{
|
|
835
921
|
address: this.address,
|
|
@@ -838,6 +924,168 @@ export class RollupContract {
|
|
|
838
924
|
];
|
|
839
925
|
}
|
|
840
926
|
|
|
927
|
+
/**
|
|
928
|
+
* Returns a state override that patches `tempCheckpointLogs[checkpointNumber]` with every field that
|
|
929
|
+
* the L1 contract reads during `propose()` for the checkpoint that builds on top of it (proposer
|
|
930
|
+
* pipelining simulation). Mirrors the writes done by `ProposeLib.addTempCheckpointLog`.
|
|
931
|
+
*
|
|
932
|
+
* `blobCommitmentsHash` and `attestationsHash` are intentionally not exposed here — the propose path
|
|
933
|
+
* never asserts against them, so leaving them at storage zero is harmless.
|
|
934
|
+
*/
|
|
935
|
+
public async makeTempCheckpointLogOverride(
|
|
936
|
+
checkpointNumber: CheckpointNumber,
|
|
937
|
+
fields: TempCheckpointLogOverrideFields,
|
|
938
|
+
): Promise<StateOverride> {
|
|
939
|
+
const constants = await this.getRollupConstants();
|
|
940
|
+
const slotAt = (field: TempCheckpointLogField) =>
|
|
941
|
+
`0x${this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, constants).toString(16).padStart(64, '0')}` as const;
|
|
942
|
+
const word = (v: bigint) => `0x${v.toString(16).padStart(64, '0')}` as const;
|
|
943
|
+
|
|
944
|
+
const stateDiff: { slot: `0x${string}`; value: `0x${string}` }[] = [];
|
|
945
|
+
|
|
946
|
+
if (fields.headerHash) {
|
|
947
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.HeaderHash), value: fields.headerHash.toString() });
|
|
948
|
+
}
|
|
949
|
+
if (fields.outHash) {
|
|
950
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.OutHash), value: fields.outHash.toString() });
|
|
951
|
+
}
|
|
952
|
+
if (fields.payloadDigest) {
|
|
953
|
+
stateDiff.push({
|
|
954
|
+
slot: slotAt(TempCheckpointLogField.PayloadDigest),
|
|
955
|
+
value: fields.payloadDigest.toString() as `0x${string}`,
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
if (fields.slotNumber !== undefined) {
|
|
959
|
+
// CompressedSlot is uint32 on L1 (SafeCast.toUint32 reverts on overflow). Match that behavior here
|
|
960
|
+
// so a malformed override surfaces immediately rather than silently truncating into a wrong slot.
|
|
961
|
+
const slotNumber = BigInt(fields.slotNumber);
|
|
962
|
+
if (slotNumber < 0n || slotNumber > 0xffffffffn) {
|
|
963
|
+
throw new Error(`slotNumber ${slotNumber} does not fit in uint32`);
|
|
964
|
+
}
|
|
965
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.SlotNumber), value: word(slotNumber) });
|
|
966
|
+
}
|
|
967
|
+
if (fields.feeHeader) {
|
|
968
|
+
stateDiff.push({
|
|
969
|
+
slot: slotAt(TempCheckpointLogField.FeeHeader),
|
|
970
|
+
value: word(RollupContract.compressFeeHeader(fields.feeHeader)),
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (stateDiff.length === 0) {
|
|
975
|
+
return [];
|
|
976
|
+
}
|
|
977
|
+
return [{ address: this.address, stateDiff }];
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Returns a state override that sets archives[checkpointNumber] to the given archive value.
|
|
982
|
+
* Used when simulating a canProposeAtTime call where the local archive differs from L1
|
|
983
|
+
* (e.g. pipelining where the parent checkpoint hasn't landed on L1 yet).
|
|
984
|
+
*/
|
|
985
|
+
public makeArchiveOverride(checkpointNumber: CheckpointNumber, archive: Fr): StateOverride {
|
|
986
|
+
const archivesMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 1n;
|
|
987
|
+
const archiveSlot = hexToBigInt(
|
|
988
|
+
keccak256(
|
|
989
|
+
encodeAbiParameters(
|
|
990
|
+
[{ type: 'uint256' }, { type: 'uint256' }],
|
|
991
|
+
[BigInt(checkpointNumber), archivesMappingBase],
|
|
992
|
+
),
|
|
993
|
+
),
|
|
994
|
+
);
|
|
995
|
+
return [
|
|
996
|
+
{
|
|
997
|
+
address: this.address,
|
|
998
|
+
stateDiff: [
|
|
999
|
+
{
|
|
1000
|
+
slot: `0x${archiveSlot.toString(16).padStart(64, '0')}`,
|
|
1001
|
+
value: archive.toString(),
|
|
1002
|
+
},
|
|
1003
|
+
],
|
|
1004
|
+
},
|
|
1005
|
+
];
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/** Merges multiple StateOverride arrays, combining stateDiff entries for the same address. */
|
|
1009
|
+
public static mergeStateOverrides(...overrides: StateOverride[]): StateOverride {
|
|
1010
|
+
type StateDiffEntry = { slot: `0x${string}`; value: `0x${string}` };
|
|
1011
|
+
const byAddress = new Map<string, { address: `0x${string}`; balance?: bigint; stateDiff: StateDiffEntry[] }>();
|
|
1012
|
+
for (const override of overrides) {
|
|
1013
|
+
for (const entry of override) {
|
|
1014
|
+
const key = entry.address.toLowerCase();
|
|
1015
|
+
const existing = byAddress.get(key);
|
|
1016
|
+
if (existing) {
|
|
1017
|
+
existing.stateDiff.push(...(entry.stateDiff ?? []));
|
|
1018
|
+
if (entry.balance !== undefined) {
|
|
1019
|
+
existing.balance = entry.balance;
|
|
1020
|
+
}
|
|
1021
|
+
} else {
|
|
1022
|
+
byAddress.set(key, {
|
|
1023
|
+
address: entry.address,
|
|
1024
|
+
balance: entry.balance,
|
|
1025
|
+
stateDiff: [...(entry.stateDiff ?? [])],
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
return [...byAddress.values()];
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/** Compresses a FeeHeader into a uint256 matching FeeHeaderLib.compress() in FeeStructs.sol. */
|
|
1034
|
+
public static compressFeeHeader(feeHeader: FeeHeader): bigint {
|
|
1035
|
+
const MASK_48_BITS = (1n << 48n) - 1n;
|
|
1036
|
+
const MASK_64_BITS = (1n << 64n) - 1n;
|
|
1037
|
+
const MASK_63_BITS = (1n << 63n) - 1n;
|
|
1038
|
+
|
|
1039
|
+
let value = BigInt(feeHeader.manaUsed) & ((1n << 32n) - 1n); // bits [0:31]
|
|
1040
|
+
value |= (feeHeader.excessMana < MASK_48_BITS ? feeHeader.excessMana : MASK_48_BITS) << 32n; // bits [32:79]
|
|
1041
|
+
value |= (BigInt(feeHeader.ethPerFeeAsset) & MASK_48_BITS) << 80n; // bits [80:127]
|
|
1042
|
+
value |= (feeHeader.congestionCost < MASK_64_BITS ? feeHeader.congestionCost : MASK_64_BITS) << 128n; // bits [128:191]
|
|
1043
|
+
value |= (feeHeader.proverCost < MASK_63_BITS ? feeHeader.proverCost : MASK_63_BITS) << 192n; // bits [192:254]
|
|
1044
|
+
value |= 1n << 255n; // preheat flag
|
|
1045
|
+
return value;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/** Computes the fee header for a child checkpoint given parent fee header and child data.
|
|
1049
|
+
* Must stay in sync with Solidity FeeLib.sol (computeNewEthPerFeeAsset, clampedAdd). */
|
|
1050
|
+
public static computeChildFeeHeader(
|
|
1051
|
+
parentFeeHeader: FeeHeader,
|
|
1052
|
+
childManaUsed: bigint,
|
|
1053
|
+
feeAssetPriceModifier: bigint,
|
|
1054
|
+
manaTarget: bigint,
|
|
1055
|
+
): FeeHeader {
|
|
1056
|
+
const MIN_ETH_PER_FEE_ASSET = 100n;
|
|
1057
|
+
const MAX_ETH_PER_FEE_ASSET = 100_000_000_000_000n; // 1e14, matches FeeLib.sol
|
|
1058
|
+
|
|
1059
|
+
// excessMana = clampedAdd(parent.excessMana + parent.manaUsed, -manaTarget)
|
|
1060
|
+
const sum = parentFeeHeader.excessMana + parentFeeHeader.manaUsed;
|
|
1061
|
+
const excessMana = sum > manaTarget ? sum - manaTarget : 0n;
|
|
1062
|
+
|
|
1063
|
+
// ethPerFeeAsset = computeNewEthPerFeeAsset(max(parent.ethPerFeeAsset, MIN), modifier)
|
|
1064
|
+
const parentPrice =
|
|
1065
|
+
parentFeeHeader.ethPerFeeAsset > MIN_ETH_PER_FEE_ASSET ? parentFeeHeader.ethPerFeeAsset : MIN_ETH_PER_FEE_ASSET;
|
|
1066
|
+
let newPrice: bigint;
|
|
1067
|
+
if (feeAssetPriceModifier >= 0n) {
|
|
1068
|
+
newPrice = (parentPrice * (10_000n + feeAssetPriceModifier)) / 10_000n;
|
|
1069
|
+
} else {
|
|
1070
|
+
const absMod = -feeAssetPriceModifier;
|
|
1071
|
+
newPrice = (parentPrice * (10_000n - absMod)) / 10_000n;
|
|
1072
|
+
}
|
|
1073
|
+
if (newPrice < MIN_ETH_PER_FEE_ASSET) {
|
|
1074
|
+
newPrice = MIN_ETH_PER_FEE_ASSET;
|
|
1075
|
+
}
|
|
1076
|
+
if (newPrice > MAX_ETH_PER_FEE_ASSET) {
|
|
1077
|
+
newPrice = MAX_ETH_PER_FEE_ASSET;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
return {
|
|
1081
|
+
excessMana,
|
|
1082
|
+
manaUsed: childManaUsed,
|
|
1083
|
+
ethPerFeeAsset: newPrice,
|
|
1084
|
+
congestionCost: 0n,
|
|
1085
|
+
proverCost: 0n,
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
|
|
841
1089
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
842
1090
|
public buildInvalidateBadAttestationRequest(
|
|
843
1091
|
checkpointNumber: CheckpointNumber,
|
|
@@ -886,8 +1134,8 @@ export class RollupContract {
|
|
|
886
1134
|
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]);
|
|
887
1135
|
}
|
|
888
1136
|
|
|
889
|
-
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean): Promise<bigint> {
|
|
890
|
-
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset]);
|
|
1137
|
+
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean, stateOverride?: StateOverride): Promise<bigint> {
|
|
1138
|
+
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset], { stateOverride });
|
|
891
1139
|
}
|
|
892
1140
|
|
|
893
1141
|
async getManaMinFeeComponentsAt(timestamp: bigint, inFeeAsset: boolean): Promise<ManaMinFeeComponents> {
|
|
@@ -944,13 +1192,20 @@ export class RollupContract {
|
|
|
944
1192
|
}
|
|
945
1193
|
|
|
946
1194
|
async getAttesters(timestamp?: bigint): Promise<EthAddress[]> {
|
|
947
|
-
|
|
1195
|
+
// Pin every read to a single L1 block so the attester count and the chunked index reads
|
|
1196
|
+
// observe a consistent set. Without this, the count and each chunk default to `latest` and
|
|
1197
|
+
// can straddle a block boundary (or reorg), yielding an inconsistent or truncated set.
|
|
1198
|
+
const block = await this.client.getBlock();
|
|
1199
|
+
const blockNumber = block.number ?? undefined;
|
|
1200
|
+
const ts = timestamp ?? block.timestamp;
|
|
1201
|
+
const attesterSize = await this.getActiveAttesterCount({ blockNumber });
|
|
948
1202
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
949
|
-
const ts = timestamp ?? (await this.client.getBlock()).timestamp;
|
|
950
1203
|
const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i));
|
|
951
1204
|
const chunks = chunk(indices, 1000);
|
|
952
1205
|
|
|
953
|
-
const results = await Promise.all(
|
|
1206
|
+
const results = await Promise.all(
|
|
1207
|
+
chunks.map(chunk => gse.getAttestersFromIndicesAtTime(this.address, ts, chunk, { blockNumber })),
|
|
1208
|
+
);
|
|
954
1209
|
return results.flat().map(addr => EthAddress.fromString(addr));
|
|
955
1210
|
}
|
|
956
1211
|
|
|
@@ -1052,7 +1307,7 @@ export class RollupContract {
|
|
|
1052
1307
|
}
|
|
1053
1308
|
|
|
1054
1309
|
public listenToCheckpointInvalidated(
|
|
1055
|
-
callback: (args: { checkpointNumber: CheckpointNumber }) => unknown,
|
|
1310
|
+
callback: (args: { checkpointNumber: CheckpointNumber; event: Log }) => unknown,
|
|
1056
1311
|
): WatchContractEventReturnType {
|
|
1057
1312
|
return this.rollup.watchEvent.CheckpointInvalidated(
|
|
1058
1313
|
{},
|
|
@@ -1061,7 +1316,7 @@ export class RollupContract {
|
|
|
1061
1316
|
for (const log of logs) {
|
|
1062
1317
|
const args = log.args;
|
|
1063
1318
|
if (args.checkpointNumber !== undefined) {
|
|
1064
|
-
callback({ checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber) });
|
|
1319
|
+
callback({ checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber), event: log });
|
|
1065
1320
|
}
|
|
1066
1321
|
}
|
|
1067
1322
|
},
|
|
@@ -1094,6 +1349,17 @@ export class RollupContract {
|
|
|
1094
1349
|
);
|
|
1095
1350
|
}
|
|
1096
1351
|
|
|
1352
|
+
/**
|
|
1353
|
+
* Fetches OwnershipTransferred events emitted on the L1 block this rollup was deployed on.
|
|
1354
|
+
* The Rollup inherits from Ownable and emits this event in its constructor, so the event
|
|
1355
|
+
* is guaranteed to exist on `l1StartBlock` for any correctly deployed rollup. Used as a
|
|
1356
|
+
* probe to detect RPC nodes that prune historical logs.
|
|
1357
|
+
*/
|
|
1358
|
+
async getOwnershipTransferredEventsAtDeploy() {
|
|
1359
|
+
const l1StartBlock = await this.getL1StartBlock();
|
|
1360
|
+
return await this.rollup.getEvents.OwnershipTransferred({}, { fromBlock: l1StartBlock, toBlock: l1StartBlock });
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1097
1363
|
/** Fetches CheckpointProposed events within the given block range. */
|
|
1098
1364
|
async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
|
|
1099
1365
|
const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
|
|
@@ -1126,4 +1392,48 @@ export class RollupContract {
|
|
|
1126
1392
|
},
|
|
1127
1393
|
}));
|
|
1128
1394
|
}
|
|
1395
|
+
|
|
1396
|
+
/** Packs pending and proven checkpoint numbers into the chain tips storage format. */
|
|
1397
|
+
static packChainTips(pendingCheckpointNumber: bigint, provenCheckpointNumber: bigint): bigint {
|
|
1398
|
+
return (pendingCheckpointNumber << 128n) | (provenCheckpointNumber & ((1n << 128n) - 1n));
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
/** Storage slot for the chain tips (offset 0 within the STF storage struct). */
|
|
1402
|
+
static get chainTipsStorageSlot(): bigint {
|
|
1403
|
+
return BigInt(RollupContract.stfStorageSlot);
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
/**
|
|
1407
|
+
* Computes the storage slot for a field within a tempCheckpointLog entry.
|
|
1408
|
+
* @param checkpointNumber - The checkpoint number
|
|
1409
|
+
* @param field - The field within the CompressedTempCheckpointLog struct
|
|
1410
|
+
*/
|
|
1411
|
+
async getTempCheckpointLogStorageSlot(
|
|
1412
|
+
checkpointNumber: CheckpointNumber,
|
|
1413
|
+
field: TempCheckpointLogField,
|
|
1414
|
+
): Promise<bigint> {
|
|
1415
|
+
const [epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
1416
|
+
this.getEpochDuration(),
|
|
1417
|
+
this.getProofSubmissionEpochs(),
|
|
1418
|
+
]);
|
|
1419
|
+
return this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, { epochDuration, proofSubmissionEpochs });
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
private computeTempCheckpointLogStorageSlot(
|
|
1423
|
+
checkpointNumber: CheckpointNumber,
|
|
1424
|
+
field: TempCheckpointLogField,
|
|
1425
|
+
constants: { epochDuration: number; proofSubmissionEpochs: number },
|
|
1426
|
+
): bigint {
|
|
1427
|
+
const fieldOffset = BigInt(field);
|
|
1428
|
+
const { epochDuration, proofSubmissionEpochs } = constants;
|
|
1429
|
+
const roundaboutSize = BigInt(epochDuration) * (BigInt(proofSubmissionEpochs) + 1n) + 1n;
|
|
1430
|
+
const tempCheckpointLogsBase = BigInt(RollupContract.stfStorageSlot) + 2n;
|
|
1431
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
1432
|
+
const entryBase = BigInt(
|
|
1433
|
+
keccak256(
|
|
1434
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsBase]),
|
|
1435
|
+
),
|
|
1436
|
+
);
|
|
1437
|
+
return entryBase + fieldOffset;
|
|
1438
|
+
}
|
|
1129
1439
|
}
|