@aztec/ethereum 0.0.1-commit.c2eed6949 → 0.0.1-commit.c52d6e7
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 +135 -35
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +226 -15
- package/dest/contracts/governance_proposer.d.ts +33 -4
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +52 -13
- package/dest/contracts/gse.d.ts +8 -2
- package/dest/contracts/gse.d.ts.map +1 -1
- package/dest/contracts/gse.js +11 -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 +5408 -25
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +349 -66
- package/dest/contracts/slashing_proposer.d.ts +170 -0
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/slashing_proposer.js +748 -0
- 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 +28 -17
- package/dest/foundry_binary.d.ts +13 -0
- package/dest/foundry_binary.d.ts.map +1 -0
- package/dest/foundry_binary.js +52 -0
- package/dest/l1_artifacts.d.ts +14943 -16270
- 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 +9 -1
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +138 -57
- 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/test/start_anvil.d.ts +1 -1
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +41 -5
- 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 +310 -10
- package/src/contracts/governance_proposer.ts +56 -13
- package/src/contracts/gse.ts +19 -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 +389 -63
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +91 -30
- package/src/deploy_aztec_l1_contracts.ts +32 -18
- package/src/foundry_binary.ts +57 -0
- 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 +122 -48
- 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/test/start_anvil.ts +38 -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 +0 -140
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/tally_slashing_proposer.js +0 -320
- 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
|
@@ -4,7 +4,9 @@ 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';
|
|
9
|
+
import { getErrorCause } from '@aztec/foundation/types';
|
|
8
10
|
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
9
11
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
10
12
|
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
@@ -12,10 +14,15 @@ import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
|
12
14
|
import chunk from 'lodash.chunk';
|
|
13
15
|
import {
|
|
14
16
|
type Account,
|
|
17
|
+
ContractFunctionRevertedError,
|
|
15
18
|
type GetContractReturnType,
|
|
16
19
|
type Hex,
|
|
20
|
+
type Log,
|
|
21
|
+
RpcRequestError,
|
|
17
22
|
type StateOverride,
|
|
18
23
|
type WatchContractEventReturnType,
|
|
24
|
+
decodeErrorResult,
|
|
25
|
+
encodeAbiParameters,
|
|
19
26
|
encodeFunctionData,
|
|
20
27
|
getContract,
|
|
21
28
|
hexToBigInt,
|
|
@@ -29,11 +36,10 @@ import type { L1ReaderConfig } from '../l1_reader.js';
|
|
|
29
36
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
30
37
|
import type { ViemClient } from '../types.js';
|
|
31
38
|
import { formatViemError } from '../utils.js';
|
|
32
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
33
39
|
import { GSEContract } from './gse.js';
|
|
34
40
|
import type { L1EventLog } from './log.js';
|
|
35
41
|
import { SlasherContract } from './slasher_contract.js';
|
|
36
|
-
import {
|
|
42
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
37
43
|
import { checkBlockTag } from './utils.js';
|
|
38
44
|
|
|
39
45
|
export type ViemCommitteeAttestation = {
|
|
@@ -55,7 +61,6 @@ export type L1RollupContractAddresses = Pick<
|
|
|
55
61
|
| 'feeJuiceAddress'
|
|
56
62
|
| 'stakingAssetAddress'
|
|
57
63
|
| 'rewardDistributorAddress'
|
|
58
|
-
| 'slashFactoryAddress'
|
|
59
64
|
| 'gseAddress'
|
|
60
65
|
>;
|
|
61
66
|
|
|
@@ -78,6 +83,7 @@ export type ViemHeader = {
|
|
|
78
83
|
feeRecipient: `0x${string}`;
|
|
79
84
|
gasFees: ViemGasFees;
|
|
80
85
|
totalManaUsed: bigint;
|
|
86
|
+
accumulatedFees: bigint;
|
|
81
87
|
};
|
|
82
88
|
|
|
83
89
|
export type ViemGasFees = {
|
|
@@ -85,12 +91,6 @@ export type ViemGasFees = {
|
|
|
85
91
|
feePerL2Gas: bigint;
|
|
86
92
|
};
|
|
87
93
|
|
|
88
|
-
export enum SlashingProposerType {
|
|
89
|
-
None = 0,
|
|
90
|
-
Tally = 1,
|
|
91
|
-
Empire = 2,
|
|
92
|
-
}
|
|
93
|
-
|
|
94
94
|
/**
|
|
95
95
|
* Status of a validator/attester in the staking system.
|
|
96
96
|
* Matches the Status enum in StakingLib.sol
|
|
@@ -134,6 +134,31 @@ export type L1FeeData = {
|
|
|
134
134
|
blobFee: bigint;
|
|
135
135
|
};
|
|
136
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
|
+
|
|
137
162
|
/** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
|
|
138
163
|
export type ManaMinFeeComponents = {
|
|
139
164
|
sequencerCost: bigint;
|
|
@@ -210,8 +235,35 @@ export type CheckpointProposedArgs = {
|
|
|
210
235
|
/** Log type for CheckpointProposed events. */
|
|
211
236
|
export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
212
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
|
+
|
|
213
264
|
export class RollupContract {
|
|
214
265
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
266
|
+
private readonly logger = createLogger('ethereum:rollup');
|
|
215
267
|
|
|
216
268
|
private static cachedStfStorageSlot: Hex | undefined;
|
|
217
269
|
private cachedEscapeHatch?: {
|
|
@@ -241,7 +293,7 @@ export class RollupContract {
|
|
|
241
293
|
|
|
242
294
|
static getFromConfig(config: L1ReaderConfig) {
|
|
243
295
|
const client = getPublicClient(config);
|
|
244
|
-
const address = config.
|
|
296
|
+
const address = config.rollupAddress.toString();
|
|
245
297
|
return new RollupContract(client, address);
|
|
246
298
|
}
|
|
247
299
|
|
|
@@ -267,34 +319,18 @@ export class RollupContract {
|
|
|
267
319
|
return this.rollup;
|
|
268
320
|
}
|
|
269
321
|
|
|
270
|
-
public async getSlashingProposer(): Promise<
|
|
271
|
-
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
272
|
-
> {
|
|
322
|
+
public async getSlashingProposer(): Promise<SlashingProposerContract | undefined> {
|
|
273
323
|
const slasher = await this.getSlasherContract();
|
|
274
324
|
if (!slasher) {
|
|
275
325
|
return undefined;
|
|
276
326
|
}
|
|
277
327
|
|
|
278
328
|
const proposerAddress = await slasher.getProposer();
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
type: 'function',
|
|
282
|
-
name: 'SLASHING_PROPOSER_TYPE',
|
|
283
|
-
inputs: [],
|
|
284
|
-
outputs: [{ name: '', type: 'uint8', internalType: 'enum SlasherFlavor' }],
|
|
285
|
-
stateMutability: 'view',
|
|
286
|
-
},
|
|
287
|
-
] as const;
|
|
288
|
-
|
|
289
|
-
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
|
|
290
|
-
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
291
|
-
if (proposerType === SlashingProposerType.Tally.valueOf()) {
|
|
292
|
-
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
293
|
-
} else if (proposerType === SlashingProposerType.Empire.valueOf()) {
|
|
294
|
-
return new EmpireSlashingProposerContract(this.client, proposerAddress);
|
|
295
|
-
} else {
|
|
296
|
-
throw new Error(`Unknown slashing proposer type: ${proposerType}`);
|
|
329
|
+
if (proposerAddress.isZero()) {
|
|
330
|
+
return undefined;
|
|
297
331
|
}
|
|
332
|
+
|
|
333
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
298
334
|
}
|
|
299
335
|
|
|
300
336
|
@memoize
|
|
@@ -495,7 +531,11 @@ export class RollupContract {
|
|
|
495
531
|
|
|
496
532
|
const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
|
|
497
533
|
return isOpen;
|
|
498
|
-
} catch {
|
|
534
|
+
} catch (err) {
|
|
535
|
+
this.logger.warn('isEscapeHatchOpen failed (treating as closed); RPC or contract error may cause liveness risk', {
|
|
536
|
+
epoch: Number(epoch),
|
|
537
|
+
error: err,
|
|
538
|
+
});
|
|
499
539
|
return false;
|
|
500
540
|
}
|
|
501
541
|
}
|
|
@@ -515,8 +555,19 @@ export class RollupContract {
|
|
|
515
555
|
return EthAddress.fromString(await this.rollup.read.owner());
|
|
516
556
|
}
|
|
517
557
|
|
|
518
|
-
async getActiveAttesterCount(): Promise<number> {
|
|
519
|
-
|
|
558
|
+
async getActiveAttesterCount(options?: { blockNumber?: bigint }): Promise<number> {
|
|
559
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
560
|
+
return Number(await this.rollup.read.getActiveAttesterCount(options));
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Number of attesters that were staked at the given (historical) L1 timestamp. This is the count that
|
|
565
|
+
* validator-set sampling uses to decide whether an epoch gets a committee, and the historical counterpart
|
|
566
|
+
* of {@link getActiveAttesterCount} (which reads at the latest L1 block).
|
|
567
|
+
*/
|
|
568
|
+
async getAttesterCountAtTime(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<number> {
|
|
569
|
+
const gse = new GSEContract(this.client, await this.getGSE());
|
|
570
|
+
return gse.getAttesterCountAtTime(this.address, timestamp, options);
|
|
520
571
|
}
|
|
521
572
|
|
|
522
573
|
public async getSlashingProposerAddress() {
|
|
@@ -531,8 +582,9 @@ export class RollupContract {
|
|
|
531
582
|
return this.rollup.read.getCheckpointReward();
|
|
532
583
|
}
|
|
533
584
|
|
|
534
|
-
async getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
535
|
-
|
|
585
|
+
async getCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
586
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
587
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber(options));
|
|
536
588
|
}
|
|
537
589
|
|
|
538
590
|
async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
@@ -540,18 +592,31 @@ export class RollupContract {
|
|
|
540
592
|
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
541
593
|
}
|
|
542
594
|
|
|
543
|
-
async getSlotNumber(): Promise<SlotNumber> {
|
|
544
|
-
|
|
595
|
+
async getSlotNumber(options?: { blockNumber?: bigint }): Promise<SlotNumber> {
|
|
596
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
597
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot(options));
|
|
545
598
|
}
|
|
546
599
|
|
|
547
|
-
async getL1FeesAt(timestamp: bigint): Promise<L1FeeData> {
|
|
548
|
-
|
|
600
|
+
async getL1FeesAt(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<L1FeeData> {
|
|
601
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
602
|
+
const result = await this.rollup.read.getL1FeesAt([timestamp], options);
|
|
549
603
|
return {
|
|
550
604
|
baseFee: result.baseFee,
|
|
551
605
|
blobFee: result.blobFee,
|
|
552
606
|
};
|
|
553
607
|
}
|
|
554
608
|
|
|
609
|
+
async getFeeHeader(checkpointNumber: bigint): Promise<FeeHeader> {
|
|
610
|
+
const result = await this.rollup.read.getFeeHeader([checkpointNumber]);
|
|
611
|
+
return {
|
|
612
|
+
excessMana: result.excessMana,
|
|
613
|
+
manaUsed: result.manaUsed,
|
|
614
|
+
ethPerFeeAsset: result.ethPerFeeAsset,
|
|
615
|
+
congestionCost: result.congestionCost,
|
|
616
|
+
proverCost: result.proverCost,
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
|
|
555
620
|
getEthPerFeeAsset(): Promise<bigint> {
|
|
556
621
|
return this.rollup.read.getEthPerFeeAsset();
|
|
557
622
|
}
|
|
@@ -565,7 +630,7 @@ export class RollupContract {
|
|
|
565
630
|
args: [timestamp],
|
|
566
631
|
})
|
|
567
632
|
.catch(e => {
|
|
568
|
-
if (e
|
|
633
|
+
if (isValidatorSelectionError(e, INSUFFICIENT_VALIDATOR_SET_SIZE_ERROR)) {
|
|
569
634
|
return { result: undefined };
|
|
570
635
|
}
|
|
571
636
|
throw e;
|
|
@@ -595,7 +660,7 @@ export class RollupContract {
|
|
|
595
660
|
args: [],
|
|
596
661
|
})
|
|
597
662
|
.catch(e => {
|
|
598
|
-
if (e
|
|
663
|
+
if (isValidatorSelectionError(e, INSUFFICIENT_VALIDATOR_SET_SIZE_ERROR)) {
|
|
599
664
|
return { result: undefined };
|
|
600
665
|
}
|
|
601
666
|
throw e;
|
|
@@ -626,8 +691,9 @@ export class RollupContract {
|
|
|
626
691
|
return EthAddress.fromString(result);
|
|
627
692
|
}
|
|
628
693
|
|
|
629
|
-
async getCheckpoint(checkpointNumber: CheckpointNumber): Promise<CheckpointLog> {
|
|
630
|
-
|
|
694
|
+
async getCheckpoint(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise<CheckpointLog> {
|
|
695
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
696
|
+
const result = await this.rollup.read.getCheckpoint([BigInt(checkpointNumber)], options);
|
|
631
697
|
return {
|
|
632
698
|
archive: Fr.fromString(result.archive),
|
|
633
699
|
headerHash: Buffer32.fromString(result.headerHash),
|
|
@@ -660,6 +726,30 @@ export class RollupContract {
|
|
|
660
726
|
);
|
|
661
727
|
}
|
|
662
728
|
|
|
729
|
+
/**
|
|
730
|
+
* Returns the effective pending checkpoint, accounting for potential prunes.
|
|
731
|
+
* When a prune can happen, the L1 contract uses the proven checkpoint instead of the pending one.
|
|
732
|
+
* This mirrors the behavior of getEffectivePendingCheckpointNumber in STFLib.sol.
|
|
733
|
+
* @param atTimestamp - The timestamp to evaluate pruneability at. Defaults to the current L1 block timestamp.
|
|
734
|
+
* @param options - Optional L1 block number to pin the queries to.
|
|
735
|
+
*/
|
|
736
|
+
getEffectivePendingCheckpoint(atTimestamp?: bigint, options?: { blockNumber?: bigint }) {
|
|
737
|
+
return retry(
|
|
738
|
+
async () => {
|
|
739
|
+
const timestamp = atTimestamp ?? (await this.client.getBlock()).timestamp;
|
|
740
|
+
const canPrune = await this.canPruneAtTime(timestamp, options);
|
|
741
|
+
if (canPrune) {
|
|
742
|
+
const provenCheckpointNumber = await this.getProvenCheckpointNumber(options);
|
|
743
|
+
return await this.getCheckpoint(provenCheckpointNumber, options);
|
|
744
|
+
}
|
|
745
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber(options);
|
|
746
|
+
return await this.getCheckpoint(pendingCheckpointNumber, options);
|
|
747
|
+
},
|
|
748
|
+
'getting effective pending checkpoint',
|
|
749
|
+
makeBackoff([0.5, 0.5, 0.5]),
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
|
|
663
753
|
async getTips(): Promise<{ pending: CheckpointNumber; proven: CheckpointNumber }> {
|
|
664
754
|
const { pending, proven } = await this.rollup.read.getTips();
|
|
665
755
|
return {
|
|
@@ -734,7 +824,7 @@ export class RollupContract {
|
|
|
734
824
|
}
|
|
735
825
|
|
|
736
826
|
async getEpochProofPublicInputs(
|
|
737
|
-
args: readonly [bigint, bigint, EpochProofPublicInputArgs, readonly
|
|
827
|
+
args: readonly [bigint, bigint, EpochProofPublicInputArgs, readonly ViemHeader[], `0x${string}`],
|
|
738
828
|
): Promise<Fr[]> {
|
|
739
829
|
const result = await this.rollup.read.getEpochProofPublicInputs(args);
|
|
740
830
|
return result.map(Fr.fromString);
|
|
@@ -782,7 +872,7 @@ export class RollupContract {
|
|
|
782
872
|
archive: Buffer,
|
|
783
873
|
account: `0x${string}` | Account,
|
|
784
874
|
timestamp: bigint,
|
|
785
|
-
|
|
875
|
+
stateOverride: StateOverride = [],
|
|
786
876
|
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
787
877
|
const timeOfNextL1Slot = timestamp;
|
|
788
878
|
const who = typeof account === 'string' ? account : account.address;
|
|
@@ -796,7 +886,7 @@ export class RollupContract {
|
|
|
796
886
|
functionName: 'canProposeAtTime',
|
|
797
887
|
args: [timeOfNextL1Slot, `0x${archive.toString('hex')}`, who],
|
|
798
888
|
account,
|
|
799
|
-
stateOverride
|
|
889
|
+
stateOverride,
|
|
800
890
|
});
|
|
801
891
|
|
|
802
892
|
return {
|
|
@@ -810,20 +900,32 @@ export class RollupContract {
|
|
|
810
900
|
}
|
|
811
901
|
|
|
812
902
|
/**
|
|
813
|
-
* Returns a state override that sets the pending
|
|
814
|
-
*
|
|
815
|
-
*
|
|
903
|
+
* Returns a state override that sets the pending and/or proven checkpoint numbers. Useful for simulations.
|
|
904
|
+
* Both values share a single storage slot (pending in the upper 128 bits, proven in the lower 128 bits), so
|
|
905
|
+
* a single combined override is emitted to avoid the second state-diff clobbering the first. The current live
|
|
906
|
+
* value is read once to preserve any half not being overridden. Returns an empty override if neither is set.
|
|
907
|
+
*
|
|
908
|
+
* Throws if the resulting `proven > pending`, which would crash the simulation: `STFLib.canPruneAtTime` calls
|
|
909
|
+
* `getEpochForCheckpoint(proven + 1)` whenever `pending != proven`, and that asserts `_n <= tips.pending`.
|
|
816
910
|
*/
|
|
817
|
-
public async
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
911
|
+
public async makeChainTipsOverride(override: {
|
|
912
|
+
pending?: CheckpointNumber;
|
|
913
|
+
proven?: CheckpointNumber;
|
|
914
|
+
}): Promise<StateOverride> {
|
|
915
|
+
if (override.pending === undefined && override.proven === undefined) {
|
|
821
916
|
return [];
|
|
822
917
|
}
|
|
823
918
|
const slot = RollupContract.stfStorageSlot;
|
|
824
919
|
const currentValue = await this.client.getStorageAt({ address: this.address, slot });
|
|
825
|
-
const
|
|
826
|
-
const
|
|
920
|
+
const currentRaw = currentValue ? hexToBigInt(currentValue) : 0n;
|
|
921
|
+
const currentPending = currentRaw >> 128n;
|
|
922
|
+
const currentProven = currentRaw & ((1n << 128n) - 1n);
|
|
923
|
+
const newPending = override.pending !== undefined ? BigInt(override.pending) : currentPending;
|
|
924
|
+
const newProven = override.proven !== undefined ? BigInt(override.proven) : currentProven;
|
|
925
|
+
if (newProven > newPending) {
|
|
926
|
+
throw new Error(`Invalid chain tips override: proven (${newProven}) > pending (${newPending})`);
|
|
927
|
+
}
|
|
928
|
+
const newValue = (newPending << 128n) | newProven;
|
|
827
929
|
return [
|
|
828
930
|
{
|
|
829
931
|
address: this.address,
|
|
@@ -832,6 +934,168 @@ export class RollupContract {
|
|
|
832
934
|
];
|
|
833
935
|
}
|
|
834
936
|
|
|
937
|
+
/**
|
|
938
|
+
* Returns a state override that patches `tempCheckpointLogs[checkpointNumber]` with every field that
|
|
939
|
+
* the L1 contract reads during `propose()` for the checkpoint that builds on top of it (proposer
|
|
940
|
+
* pipelining simulation). Mirrors the writes done by `ProposeLib.addTempCheckpointLog`.
|
|
941
|
+
*
|
|
942
|
+
* `blobCommitmentsHash` and `attestationsHash` are intentionally not exposed here — the propose path
|
|
943
|
+
* never asserts against them, so leaving them at storage zero is harmless.
|
|
944
|
+
*/
|
|
945
|
+
public async makeTempCheckpointLogOverride(
|
|
946
|
+
checkpointNumber: CheckpointNumber,
|
|
947
|
+
fields: TempCheckpointLogOverrideFields,
|
|
948
|
+
): Promise<StateOverride> {
|
|
949
|
+
const constants = await this.getRollupConstants();
|
|
950
|
+
const slotAt = (field: TempCheckpointLogField) =>
|
|
951
|
+
`0x${this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, constants).toString(16).padStart(64, '0')}` as const;
|
|
952
|
+
const word = (v: bigint) => `0x${v.toString(16).padStart(64, '0')}` as const;
|
|
953
|
+
|
|
954
|
+
const stateDiff: { slot: `0x${string}`; value: `0x${string}` }[] = [];
|
|
955
|
+
|
|
956
|
+
if (fields.headerHash) {
|
|
957
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.HeaderHash), value: fields.headerHash.toString() });
|
|
958
|
+
}
|
|
959
|
+
if (fields.outHash) {
|
|
960
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.OutHash), value: fields.outHash.toString() });
|
|
961
|
+
}
|
|
962
|
+
if (fields.payloadDigest) {
|
|
963
|
+
stateDiff.push({
|
|
964
|
+
slot: slotAt(TempCheckpointLogField.PayloadDigest),
|
|
965
|
+
value: fields.payloadDigest.toString() as `0x${string}`,
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
if (fields.slotNumber !== undefined) {
|
|
969
|
+
// CompressedSlot is uint32 on L1 (SafeCast.toUint32 reverts on overflow). Match that behavior here
|
|
970
|
+
// so a malformed override surfaces immediately rather than silently truncating into a wrong slot.
|
|
971
|
+
const slotNumber = BigInt(fields.slotNumber);
|
|
972
|
+
if (slotNumber < 0n || slotNumber > 0xffffffffn) {
|
|
973
|
+
throw new Error(`slotNumber ${slotNumber} does not fit in uint32`);
|
|
974
|
+
}
|
|
975
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.SlotNumber), value: word(slotNumber) });
|
|
976
|
+
}
|
|
977
|
+
if (fields.feeHeader) {
|
|
978
|
+
stateDiff.push({
|
|
979
|
+
slot: slotAt(TempCheckpointLogField.FeeHeader),
|
|
980
|
+
value: word(RollupContract.compressFeeHeader(fields.feeHeader)),
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
if (stateDiff.length === 0) {
|
|
985
|
+
return [];
|
|
986
|
+
}
|
|
987
|
+
return [{ address: this.address, stateDiff }];
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
/**
|
|
991
|
+
* Returns a state override that sets archives[checkpointNumber] to the given archive value.
|
|
992
|
+
* Used when simulating a canProposeAtTime call where the local archive differs from L1
|
|
993
|
+
* (e.g. pipelining where the parent checkpoint hasn't landed on L1 yet).
|
|
994
|
+
*/
|
|
995
|
+
public makeArchiveOverride(checkpointNumber: CheckpointNumber, archive: Fr): StateOverride {
|
|
996
|
+
const archivesMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 1n;
|
|
997
|
+
const archiveSlot = hexToBigInt(
|
|
998
|
+
keccak256(
|
|
999
|
+
encodeAbiParameters(
|
|
1000
|
+
[{ type: 'uint256' }, { type: 'uint256' }],
|
|
1001
|
+
[BigInt(checkpointNumber), archivesMappingBase],
|
|
1002
|
+
),
|
|
1003
|
+
),
|
|
1004
|
+
);
|
|
1005
|
+
return [
|
|
1006
|
+
{
|
|
1007
|
+
address: this.address,
|
|
1008
|
+
stateDiff: [
|
|
1009
|
+
{
|
|
1010
|
+
slot: `0x${archiveSlot.toString(16).padStart(64, '0')}`,
|
|
1011
|
+
value: archive.toString(),
|
|
1012
|
+
},
|
|
1013
|
+
],
|
|
1014
|
+
},
|
|
1015
|
+
];
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/** Merges multiple StateOverride arrays, combining stateDiff entries for the same address. */
|
|
1019
|
+
public static mergeStateOverrides(...overrides: StateOverride[]): StateOverride {
|
|
1020
|
+
type StateDiffEntry = { slot: `0x${string}`; value: `0x${string}` };
|
|
1021
|
+
const byAddress = new Map<string, { address: `0x${string}`; balance?: bigint; stateDiff: StateDiffEntry[] }>();
|
|
1022
|
+
for (const override of overrides) {
|
|
1023
|
+
for (const entry of override) {
|
|
1024
|
+
const key = entry.address.toLowerCase();
|
|
1025
|
+
const existing = byAddress.get(key);
|
|
1026
|
+
if (existing) {
|
|
1027
|
+
existing.stateDiff.push(...(entry.stateDiff ?? []));
|
|
1028
|
+
if (entry.balance !== undefined) {
|
|
1029
|
+
existing.balance = entry.balance;
|
|
1030
|
+
}
|
|
1031
|
+
} else {
|
|
1032
|
+
byAddress.set(key, {
|
|
1033
|
+
address: entry.address,
|
|
1034
|
+
balance: entry.balance,
|
|
1035
|
+
stateDiff: [...(entry.stateDiff ?? [])],
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
return [...byAddress.values()];
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
/** Compresses a FeeHeader into a uint256 matching FeeHeaderLib.compress() in FeeStructs.sol. */
|
|
1044
|
+
public static compressFeeHeader(feeHeader: FeeHeader): bigint {
|
|
1045
|
+
const MASK_48_BITS = (1n << 48n) - 1n;
|
|
1046
|
+
const MASK_64_BITS = (1n << 64n) - 1n;
|
|
1047
|
+
const MASK_63_BITS = (1n << 63n) - 1n;
|
|
1048
|
+
|
|
1049
|
+
let value = BigInt(feeHeader.manaUsed) & ((1n << 32n) - 1n); // bits [0:31]
|
|
1050
|
+
value |= (feeHeader.excessMana < MASK_48_BITS ? feeHeader.excessMana : MASK_48_BITS) << 32n; // bits [32:79]
|
|
1051
|
+
value |= (BigInt(feeHeader.ethPerFeeAsset) & MASK_48_BITS) << 80n; // bits [80:127]
|
|
1052
|
+
value |= (feeHeader.congestionCost < MASK_64_BITS ? feeHeader.congestionCost : MASK_64_BITS) << 128n; // bits [128:191]
|
|
1053
|
+
value |= (feeHeader.proverCost < MASK_63_BITS ? feeHeader.proverCost : MASK_63_BITS) << 192n; // bits [192:254]
|
|
1054
|
+
value |= 1n << 255n; // preheat flag
|
|
1055
|
+
return value;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/** Computes the fee header for a child checkpoint given parent fee header and child data.
|
|
1059
|
+
* Must stay in sync with Solidity FeeLib.sol (computeNewEthPerFeeAsset, clampedAdd). */
|
|
1060
|
+
public static computeChildFeeHeader(
|
|
1061
|
+
parentFeeHeader: FeeHeader,
|
|
1062
|
+
childManaUsed: bigint,
|
|
1063
|
+
feeAssetPriceModifier: bigint,
|
|
1064
|
+
manaTarget: bigint,
|
|
1065
|
+
): FeeHeader {
|
|
1066
|
+
const MIN_ETH_PER_FEE_ASSET = 100n;
|
|
1067
|
+
const MAX_ETH_PER_FEE_ASSET = 100_000_000_000_000n; // 1e14, matches FeeLib.sol
|
|
1068
|
+
|
|
1069
|
+
// excessMana = clampedAdd(parent.excessMana + parent.manaUsed, -manaTarget)
|
|
1070
|
+
const sum = parentFeeHeader.excessMana + parentFeeHeader.manaUsed;
|
|
1071
|
+
const excessMana = sum > manaTarget ? sum - manaTarget : 0n;
|
|
1072
|
+
|
|
1073
|
+
// ethPerFeeAsset = computeNewEthPerFeeAsset(max(parent.ethPerFeeAsset, MIN), modifier)
|
|
1074
|
+
const parentPrice =
|
|
1075
|
+
parentFeeHeader.ethPerFeeAsset > MIN_ETH_PER_FEE_ASSET ? parentFeeHeader.ethPerFeeAsset : MIN_ETH_PER_FEE_ASSET;
|
|
1076
|
+
let newPrice: bigint;
|
|
1077
|
+
if (feeAssetPriceModifier >= 0n) {
|
|
1078
|
+
newPrice = (parentPrice * (10_000n + feeAssetPriceModifier)) / 10_000n;
|
|
1079
|
+
} else {
|
|
1080
|
+
const absMod = -feeAssetPriceModifier;
|
|
1081
|
+
newPrice = (parentPrice * (10_000n - absMod)) / 10_000n;
|
|
1082
|
+
}
|
|
1083
|
+
if (newPrice < MIN_ETH_PER_FEE_ASSET) {
|
|
1084
|
+
newPrice = MIN_ETH_PER_FEE_ASSET;
|
|
1085
|
+
}
|
|
1086
|
+
if (newPrice > MAX_ETH_PER_FEE_ASSET) {
|
|
1087
|
+
newPrice = MAX_ETH_PER_FEE_ASSET;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
return {
|
|
1091
|
+
excessMana,
|
|
1092
|
+
manaUsed: childManaUsed,
|
|
1093
|
+
ethPerFeeAsset: newPrice,
|
|
1094
|
+
congestionCost: 0n,
|
|
1095
|
+
proverCost: 0n,
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
|
|
835
1099
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
836
1100
|
public buildInvalidateBadAttestationRequest(
|
|
837
1101
|
checkpointNumber: CheckpointNumber,
|
|
@@ -880,8 +1144,8 @@ export class RollupContract {
|
|
|
880
1144
|
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]);
|
|
881
1145
|
}
|
|
882
1146
|
|
|
883
|
-
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean): Promise<bigint> {
|
|
884
|
-
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset]);
|
|
1147
|
+
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean, stateOverride?: StateOverride): Promise<bigint> {
|
|
1148
|
+
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset], { stateOverride });
|
|
885
1149
|
}
|
|
886
1150
|
|
|
887
1151
|
async getManaMinFeeComponentsAt(timestamp: bigint, inFeeAsset: boolean): Promise<ManaMinFeeComponents> {
|
|
@@ -938,13 +1202,20 @@ export class RollupContract {
|
|
|
938
1202
|
}
|
|
939
1203
|
|
|
940
1204
|
async getAttesters(timestamp?: bigint): Promise<EthAddress[]> {
|
|
941
|
-
|
|
1205
|
+
// Pin every read to a single L1 block so the attester count and the chunked index reads
|
|
1206
|
+
// observe a consistent set. Without this, the count and each chunk default to `latest` and
|
|
1207
|
+
// can straddle a block boundary (or reorg), yielding an inconsistent or truncated set.
|
|
1208
|
+
const block = await this.client.getBlock();
|
|
1209
|
+
const blockNumber = block.number ?? undefined;
|
|
1210
|
+
const ts = timestamp ?? block.timestamp;
|
|
1211
|
+
const attesterSize = await this.getActiveAttesterCount({ blockNumber });
|
|
942
1212
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
943
|
-
const ts = timestamp ?? (await this.client.getBlock()).timestamp;
|
|
944
1213
|
const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i));
|
|
945
1214
|
const chunks = chunk(indices, 1000);
|
|
946
1215
|
|
|
947
|
-
const results = await Promise.all(
|
|
1216
|
+
const results = await Promise.all(
|
|
1217
|
+
chunks.map(chunk => gse.getAttestersFromIndicesAtTime(this.address, ts, chunk, { blockNumber })),
|
|
1218
|
+
);
|
|
948
1219
|
return results.flat().map(addr => EthAddress.fromString(addr));
|
|
949
1220
|
}
|
|
950
1221
|
|
|
@@ -1046,7 +1317,7 @@ export class RollupContract {
|
|
|
1046
1317
|
}
|
|
1047
1318
|
|
|
1048
1319
|
public listenToCheckpointInvalidated(
|
|
1049
|
-
callback: (args: { checkpointNumber: CheckpointNumber }) => unknown,
|
|
1320
|
+
callback: (args: { checkpointNumber: CheckpointNumber; event: Log }) => unknown,
|
|
1050
1321
|
): WatchContractEventReturnType {
|
|
1051
1322
|
return this.rollup.watchEvent.CheckpointInvalidated(
|
|
1052
1323
|
{},
|
|
@@ -1055,7 +1326,7 @@ export class RollupContract {
|
|
|
1055
1326
|
for (const log of logs) {
|
|
1056
1327
|
const args = log.args;
|
|
1057
1328
|
if (args.checkpointNumber !== undefined) {
|
|
1058
|
-
callback({ checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber) });
|
|
1329
|
+
callback({ checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber), event: log });
|
|
1059
1330
|
}
|
|
1060
1331
|
}
|
|
1061
1332
|
},
|
|
@@ -1088,6 +1359,17 @@ export class RollupContract {
|
|
|
1088
1359
|
);
|
|
1089
1360
|
}
|
|
1090
1361
|
|
|
1362
|
+
/**
|
|
1363
|
+
* Fetches OwnershipTransferred events emitted on the L1 block this rollup was deployed on.
|
|
1364
|
+
* The Rollup inherits from Ownable and emits this event in its constructor, so the event
|
|
1365
|
+
* is guaranteed to exist on `l1StartBlock` for any correctly deployed rollup. Used as a
|
|
1366
|
+
* probe to detect RPC nodes that prune historical logs.
|
|
1367
|
+
*/
|
|
1368
|
+
async getOwnershipTransferredEventsAtDeploy() {
|
|
1369
|
+
const l1StartBlock = await this.getL1StartBlock();
|
|
1370
|
+
return await this.rollup.getEvents.OwnershipTransferred({}, { fromBlock: l1StartBlock, toBlock: l1StartBlock });
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1091
1373
|
/** Fetches CheckpointProposed events within the given block range. */
|
|
1092
1374
|
async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
|
|
1093
1375
|
const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
|
|
@@ -1120,4 +1402,48 @@ export class RollupContract {
|
|
|
1120
1402
|
},
|
|
1121
1403
|
}));
|
|
1122
1404
|
}
|
|
1405
|
+
|
|
1406
|
+
/** Packs pending and proven checkpoint numbers into the chain tips storage format. */
|
|
1407
|
+
static packChainTips(pendingCheckpointNumber: bigint, provenCheckpointNumber: bigint): bigint {
|
|
1408
|
+
return (pendingCheckpointNumber << 128n) | (provenCheckpointNumber & ((1n << 128n) - 1n));
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
/** Storage slot for the chain tips (offset 0 within the STF storage struct). */
|
|
1412
|
+
static get chainTipsStorageSlot(): bigint {
|
|
1413
|
+
return BigInt(RollupContract.stfStorageSlot);
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
/**
|
|
1417
|
+
* Computes the storage slot for a field within a tempCheckpointLog entry.
|
|
1418
|
+
* @param checkpointNumber - The checkpoint number
|
|
1419
|
+
* @param field - The field within the CompressedTempCheckpointLog struct
|
|
1420
|
+
*/
|
|
1421
|
+
async getTempCheckpointLogStorageSlot(
|
|
1422
|
+
checkpointNumber: CheckpointNumber,
|
|
1423
|
+
field: TempCheckpointLogField,
|
|
1424
|
+
): Promise<bigint> {
|
|
1425
|
+
const [epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
1426
|
+
this.getEpochDuration(),
|
|
1427
|
+
this.getProofSubmissionEpochs(),
|
|
1428
|
+
]);
|
|
1429
|
+
return this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, { epochDuration, proofSubmissionEpochs });
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
private computeTempCheckpointLogStorageSlot(
|
|
1433
|
+
checkpointNumber: CheckpointNumber,
|
|
1434
|
+
field: TempCheckpointLogField,
|
|
1435
|
+
constants: { epochDuration: number; proofSubmissionEpochs: number },
|
|
1436
|
+
): bigint {
|
|
1437
|
+
const fieldOffset = BigInt(field);
|
|
1438
|
+
const { epochDuration, proofSubmissionEpochs } = constants;
|
|
1439
|
+
const roundaboutSize = BigInt(epochDuration) * (BigInt(proofSubmissionEpochs) + 1n) + 1n;
|
|
1440
|
+
const tempCheckpointLogsBase = BigInt(RollupContract.stfStorageSlot) + 2n;
|
|
1441
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
1442
|
+
const entryBase = BigInt(
|
|
1443
|
+
keccak256(
|
|
1444
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsBase]),
|
|
1445
|
+
),
|
|
1446
|
+
);
|
|
1447
|
+
return entryBase + fieldOffset;
|
|
1448
|
+
}
|
|
1123
1449
|
}
|