@aztec/ethereum 0.0.1-commit.1142ef1 → 0.0.1-commit.11bf3dd6e
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 +22 -33
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +59 -64
- package/dest/contracts/chain_state_override.d.ts +38 -0
- package/dest/contracts/chain_state_override.d.ts.map +1 -0
- package/dest/contracts/chain_state_override.js +100 -0
- package/dest/contracts/empire_base.d.ts +3 -1
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.d.ts +1 -1
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.js +2 -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.d.ts +3 -1
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +14 -4
- 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 +13 -1
- package/dest/contracts/inbox.d.ts +18 -1
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +31 -1
- package/dest/contracts/index.d.ts +5 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +4 -2
- package/dest/contracts/log.d.ts +13 -0
- package/dest/contracts/log.d.ts.map +1 -0
- package/dest/contracts/log.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 +87 -1
- 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 +117 -22
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +370 -60
- 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} +18 -13
- package/dest/deploy_aztec_l1_contracts.d.ts +9 -8
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +58 -32
- package/dest/deploy_l1_contract.js +3 -3
- package/dest/generated/l1-contracts-defaults.d.ts +30 -0
- package/dest/generated/l1-contracts-defaults.d.ts.map +1 -0
- package/dest/generated/l1-contracts-defaults.js +30 -0
- package/dest/l1_artifacts.d.ts +10713 -16120
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +9 -24
- package/dest/l1_contract_addresses.d.ts +1 -5
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +0 -6
- 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/constants.d.ts +1 -1
- package/dest/l1_tx_utils/constants.js +2 -2
- 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 +81 -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 +11 -7
- 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 -6
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +81 -7
- package/dest/queries.d.ts +2 -2
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +7 -4
- 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 +18 -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/rollup_cheat_codes.d.ts +8 -2
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +19 -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 +2 -1
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +62 -12
- package/package.json +8 -9
- package/src/client.ts +10 -2
- package/src/config.ts +75 -65
- package/src/contracts/README.md +157 -0
- package/src/contracts/chain_state_override.ts +147 -0
- package/src/contracts/empire_base.ts +2 -0
- package/src/contracts/fee_asset_handler.ts +2 -0
- package/src/contracts/fee_asset_price_oracle.ts +280 -0
- package/src/contracts/governance.ts +13 -4
- package/src/contracts/governance_proposer.ts +10 -1
- package/src/contracts/inbox.ts +48 -1
- package/src/contracts/index.ts +4 -2
- package/src/contracts/log.ts +13 -0
- package/src/contracts/multicall.ts +70 -3
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +424 -56
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +16 -14
- package/src/deploy_aztec_l1_contracts.ts +81 -40
- package/src/deploy_l1_contract.ts +3 -3
- package/src/generated/l1-contracts-defaults.ts +32 -0
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +0 -7
- package/src/l1_reader.ts +13 -1
- package/src/l1_tx_utils/config.ts +20 -0
- package/src/l1_tx_utils/constants.ts +2 -2
- 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 +74 -36
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +11 -7
- package/src/{test → l1_tx_utils}/tx_delayer.ts +78 -50
- package/src/publisher_manager.ts +107 -10
- package/src/queries.ts +6 -4
- 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/rollup_cheat_codes.ts +22 -3
- package/src/test/start_anvil.ts +177 -29
- package/src/test/upgrade_utils.ts +2 -2
- package/src/utils.ts +70 -14
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -67
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -209
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- 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/contracts/empire_slashing_proposer.ts +0 -270
- 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,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 { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
8
10
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
9
11
|
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
10
12
|
|
|
@@ -15,6 +17,7 @@ import {
|
|
|
15
17
|
type Hex,
|
|
16
18
|
type StateOverride,
|
|
17
19
|
type WatchContractEventReturnType,
|
|
20
|
+
encodeAbiParameters,
|
|
18
21
|
encodeFunctionData,
|
|
19
22
|
getContract,
|
|
20
23
|
hexToBigInt,
|
|
@@ -28,10 +31,10 @@ import type { L1ReaderConfig } from '../l1_reader.js';
|
|
|
28
31
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
29
32
|
import type { ViemClient } from '../types.js';
|
|
30
33
|
import { formatViemError } from '../utils.js';
|
|
31
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
32
34
|
import { GSEContract } from './gse.js';
|
|
35
|
+
import type { L1EventLog } from './log.js';
|
|
33
36
|
import { SlasherContract } from './slasher_contract.js';
|
|
34
|
-
import {
|
|
37
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
35
38
|
import { checkBlockTag } from './utils.js';
|
|
36
39
|
|
|
37
40
|
export type ViemCommitteeAttestation = {
|
|
@@ -53,7 +56,6 @@ export type L1RollupContractAddresses = Pick<
|
|
|
53
56
|
| 'feeJuiceAddress'
|
|
54
57
|
| 'stakingAssetAddress'
|
|
55
58
|
| 'rewardDistributorAddress'
|
|
56
|
-
| 'slashFactoryAddress'
|
|
57
59
|
| 'gseAddress'
|
|
58
60
|
>;
|
|
59
61
|
|
|
@@ -69,6 +71,7 @@ export type ViemHeader = {
|
|
|
69
71
|
blockHeadersHash: `0x${string}`;
|
|
70
72
|
blobsHash: `0x${string}`;
|
|
71
73
|
inHash: `0x${string}`;
|
|
74
|
+
outHash: `0x${string}`;
|
|
72
75
|
slotNumber: bigint;
|
|
73
76
|
timestamp: bigint;
|
|
74
77
|
coinbase: `0x${string}`;
|
|
@@ -82,12 +85,6 @@ export type ViemGasFees = {
|
|
|
82
85
|
feePerL2Gas: bigint;
|
|
83
86
|
};
|
|
84
87
|
|
|
85
|
-
export enum SlashingProposerType {
|
|
86
|
-
None = 0,
|
|
87
|
-
Tally = 1,
|
|
88
|
-
Empire = 2,
|
|
89
|
-
}
|
|
90
|
-
|
|
91
88
|
/**
|
|
92
89
|
* Status of a validator/attester in the staking system.
|
|
93
90
|
* Matches the Status enum in StakingLib.sol
|
|
@@ -105,7 +102,7 @@ export enum AttesterStatus {
|
|
|
105
102
|
export type FeeHeader = {
|
|
106
103
|
excessMana: bigint;
|
|
107
104
|
manaUsed: bigint;
|
|
108
|
-
|
|
105
|
+
ethPerFeeAsset: bigint;
|
|
109
106
|
congestionCost: bigint;
|
|
110
107
|
proverCost: bigint;
|
|
111
108
|
};
|
|
@@ -131,6 +128,25 @@ export type L1FeeData = {
|
|
|
131
128
|
blobFee: bigint;
|
|
132
129
|
};
|
|
133
130
|
|
|
131
|
+
/** Field offsets within the CompressedTempCheckpointLog struct in Solidity storage. */
|
|
132
|
+
export enum TempCheckpointLogField {
|
|
133
|
+
HeaderHash = 0,
|
|
134
|
+
BlobCommitmentsHash = 1,
|
|
135
|
+
OutHash = 2,
|
|
136
|
+
AttestationsHash = 3,
|
|
137
|
+
PayloadDigest = 4,
|
|
138
|
+
SlotNumber = 5,
|
|
139
|
+
FeeHeader = 6,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
|
|
143
|
+
export type ManaMinFeeComponents = {
|
|
144
|
+
sequencerCost: bigint;
|
|
145
|
+
proverCost: bigint;
|
|
146
|
+
congestionCost: bigint;
|
|
147
|
+
congestionMultiplier: bigint;
|
|
148
|
+
};
|
|
149
|
+
|
|
134
150
|
/**
|
|
135
151
|
* Reward configuration for the rollup
|
|
136
152
|
*/
|
|
@@ -185,10 +201,29 @@ export type RollupStatusResponse = {
|
|
|
185
201
|
archiveOfMyCheckpoint: Fr;
|
|
186
202
|
};
|
|
187
203
|
|
|
204
|
+
/** Arguments for the CheckpointProposed event. */
|
|
205
|
+
export type CheckpointProposedArgs = {
|
|
206
|
+
checkpointNumber: CheckpointNumber;
|
|
207
|
+
archive: Fr;
|
|
208
|
+
versionedBlobHashes: Buffer[];
|
|
209
|
+
/** Hash of attestations emitted in the CheckpointProposed event. */
|
|
210
|
+
attestationsHash: Buffer32;
|
|
211
|
+
/** Digest of the payload emitted in the CheckpointProposed event. */
|
|
212
|
+
payloadDigest: Buffer32;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/** Log type for CheckpointProposed events. */
|
|
216
|
+
export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
217
|
+
|
|
188
218
|
export class RollupContract {
|
|
189
219
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
220
|
+
private readonly logger = createLogger('ethereum:rollup');
|
|
190
221
|
|
|
191
222
|
private static cachedStfStorageSlot: Hex | undefined;
|
|
223
|
+
private cachedEscapeHatch?: {
|
|
224
|
+
address: EthAddress;
|
|
225
|
+
contract: GetContractReturnType<typeof EscapeHatchAbi, ViemClient>;
|
|
226
|
+
};
|
|
192
227
|
|
|
193
228
|
static get checkBlobStorageSlot(): bigint {
|
|
194
229
|
const asString = RollupStorage.find(storage => storage.label === 'checkBlob')?.slot;
|
|
@@ -238,34 +273,18 @@ export class RollupContract {
|
|
|
238
273
|
return this.rollup;
|
|
239
274
|
}
|
|
240
275
|
|
|
241
|
-
public async getSlashingProposer(): Promise<
|
|
242
|
-
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
243
|
-
> {
|
|
276
|
+
public async getSlashingProposer(): Promise<SlashingProposerContract | undefined> {
|
|
244
277
|
const slasher = await this.getSlasherContract();
|
|
245
278
|
if (!slasher) {
|
|
246
279
|
return undefined;
|
|
247
280
|
}
|
|
248
281
|
|
|
249
282
|
const proposerAddress = await slasher.getProposer();
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
type: 'function',
|
|
253
|
-
name: 'SLASHING_PROPOSER_TYPE',
|
|
254
|
-
inputs: [],
|
|
255
|
-
outputs: [{ name: '', type: 'uint8', internalType: 'enum SlasherFlavor' }],
|
|
256
|
-
stateMutability: 'view',
|
|
257
|
-
},
|
|
258
|
-
] as const;
|
|
259
|
-
|
|
260
|
-
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
|
|
261
|
-
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
262
|
-
if (proposerType === SlashingProposerType.Tally.valueOf()) {
|
|
263
|
-
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
264
|
-
} else if (proposerType === SlashingProposerType.Empire.valueOf()) {
|
|
265
|
-
return new EmpireSlashingProposerContract(this.client, proposerAddress);
|
|
266
|
-
} else {
|
|
267
|
-
throw new Error(`Unknown slashing proposer type: ${proposerType}`);
|
|
283
|
+
if (proposerAddress.isZero()) {
|
|
284
|
+
return undefined;
|
|
268
285
|
}
|
|
286
|
+
|
|
287
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
269
288
|
}
|
|
270
289
|
|
|
271
290
|
@memoize
|
|
@@ -358,6 +377,20 @@ export class RollupContract {
|
|
|
358
377
|
return Fr.fromString(await this.rollup.read.archiveAt([0n]));
|
|
359
378
|
}
|
|
360
379
|
|
|
380
|
+
@memoize
|
|
381
|
+
async getVkTreeRoot(): Promise<Fr> {
|
|
382
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 3n;
|
|
383
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
384
|
+
return Fr.fromString(value ?? '0x0');
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
@memoize
|
|
388
|
+
async getProtocolContractsHash(): Promise<Fr> {
|
|
389
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 4n;
|
|
390
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
391
|
+
return Fr.fromString(value ?? '0x0');
|
|
392
|
+
}
|
|
393
|
+
|
|
361
394
|
/**
|
|
362
395
|
* Returns rollup constants used for epoch queries.
|
|
363
396
|
* Return type is `L1RollupConstants` which is defined in stdlib,
|
|
@@ -370,13 +403,25 @@ export class RollupContract {
|
|
|
370
403
|
slotDuration: number;
|
|
371
404
|
epochDuration: number;
|
|
372
405
|
proofSubmissionEpochs: number;
|
|
406
|
+
targetCommitteeSize: number;
|
|
407
|
+
rollupManaLimit: number;
|
|
373
408
|
}> {
|
|
374
|
-
const [
|
|
409
|
+
const [
|
|
410
|
+
l1StartBlock,
|
|
411
|
+
l1GenesisTime,
|
|
412
|
+
slotDuration,
|
|
413
|
+
epochDuration,
|
|
414
|
+
proofSubmissionEpochs,
|
|
415
|
+
targetCommitteeSize,
|
|
416
|
+
rollupManaLimit,
|
|
417
|
+
] = await Promise.all([
|
|
375
418
|
this.getL1StartBlock(),
|
|
376
419
|
this.getL1GenesisTime(),
|
|
377
420
|
this.getSlotDuration(),
|
|
378
421
|
this.getEpochDuration(),
|
|
379
422
|
this.getProofSubmissionEpochs(),
|
|
423
|
+
this.getTargetCommitteeSize(),
|
|
424
|
+
this.getManaLimit(),
|
|
380
425
|
]);
|
|
381
426
|
return {
|
|
382
427
|
l1StartBlock,
|
|
@@ -384,6 +429,8 @@ export class RollupContract {
|
|
|
384
429
|
slotDuration,
|
|
385
430
|
epochDuration: Number(epochDuration),
|
|
386
431
|
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
432
|
+
targetCommitteeSize,
|
|
433
|
+
rollupManaLimit: Number(rollupManaLimit),
|
|
387
434
|
};
|
|
388
435
|
}
|
|
389
436
|
|
|
@@ -391,6 +438,62 @@ export class RollupContract {
|
|
|
391
438
|
return EthAddress.fromString(await this.rollup.read.getSlasher());
|
|
392
439
|
}
|
|
393
440
|
|
|
441
|
+
/**
|
|
442
|
+
* Returns the configured escape hatch contract address, or zero if disabled.
|
|
443
|
+
*/
|
|
444
|
+
async getEscapeHatchAddress(): Promise<EthAddress> {
|
|
445
|
+
return EthAddress.fromString(await this.rollup.read.getEscapeHatch());
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
private async getEscapeHatchContract(): Promise<
|
|
449
|
+
GetContractReturnType<typeof EscapeHatchAbi, ViemClient> | undefined
|
|
450
|
+
> {
|
|
451
|
+
const escapeHatchAddress = await this.getEscapeHatchAddress();
|
|
452
|
+
if (escapeHatchAddress.isZero()) {
|
|
453
|
+
return undefined;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Cache the viem contract wrapper since it will be used frequently.
|
|
457
|
+
if (!this.cachedEscapeHatch || !this.cachedEscapeHatch.address.equals(escapeHatchAddress)) {
|
|
458
|
+
this.cachedEscapeHatch = {
|
|
459
|
+
address: escapeHatchAddress,
|
|
460
|
+
contract: getContract({
|
|
461
|
+
address: escapeHatchAddress.toString(),
|
|
462
|
+
abi: EscapeHatchAbi,
|
|
463
|
+
client: this.client,
|
|
464
|
+
}),
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return this.cachedEscapeHatch.contract;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Returns whether the escape hatch is open for the given epoch.
|
|
473
|
+
* If escape hatch is not configured, returns false.
|
|
474
|
+
*
|
|
475
|
+
* This function is intentionally defensive: any failure to query the escape hatch
|
|
476
|
+
* (RPC issues, transient errors, etc.) is treated as "closed" to avoid callers
|
|
477
|
+
* needing to sprinkle try/catch everywhere.
|
|
478
|
+
*/
|
|
479
|
+
async isEscapeHatchOpen(epoch: EpochNumber): Promise<boolean> {
|
|
480
|
+
try {
|
|
481
|
+
const escapeHatch = await this.getEscapeHatchContract();
|
|
482
|
+
if (!escapeHatch) {
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
|
|
487
|
+
return isOpen;
|
|
488
|
+
} catch (err) {
|
|
489
|
+
this.logger.warn('isEscapeHatchOpen failed (treating as closed); RPC or contract error may cause liveness risk', {
|
|
490
|
+
epoch: Number(epoch),
|
|
491
|
+
error: err,
|
|
492
|
+
});
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
394
497
|
/**
|
|
395
498
|
* Returns a SlasherContract instance for interacting with the slasher contract.
|
|
396
499
|
*/
|
|
@@ -422,28 +525,43 @@ export class RollupContract {
|
|
|
422
525
|
return this.rollup.read.getCheckpointReward();
|
|
423
526
|
}
|
|
424
527
|
|
|
425
|
-
async getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
426
|
-
|
|
528
|
+
async getCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
529
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
530
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber(options));
|
|
427
531
|
}
|
|
428
532
|
|
|
429
|
-
async getProvenCheckpointNumber(): Promise<CheckpointNumber> {
|
|
430
|
-
|
|
533
|
+
async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
534
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
535
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
431
536
|
}
|
|
432
537
|
|
|
433
|
-
async getSlotNumber(): Promise<SlotNumber> {
|
|
434
|
-
|
|
538
|
+
async getSlotNumber(options?: { blockNumber?: bigint }): Promise<SlotNumber> {
|
|
539
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
540
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot(options));
|
|
435
541
|
}
|
|
436
542
|
|
|
437
|
-
async getL1FeesAt(timestamp: bigint): Promise<L1FeeData> {
|
|
438
|
-
|
|
543
|
+
async getL1FeesAt(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<L1FeeData> {
|
|
544
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
545
|
+
const result = await this.rollup.read.getL1FeesAt([timestamp], options);
|
|
439
546
|
return {
|
|
440
547
|
baseFee: result.baseFee,
|
|
441
548
|
blobFee: result.blobFee,
|
|
442
549
|
};
|
|
443
550
|
}
|
|
444
551
|
|
|
445
|
-
|
|
446
|
-
|
|
552
|
+
async getFeeHeader(checkpointNumber: bigint): Promise<FeeHeader> {
|
|
553
|
+
const result = await this.rollup.read.getFeeHeader([checkpointNumber]);
|
|
554
|
+
return {
|
|
555
|
+
excessMana: result.excessMana,
|
|
556
|
+
manaUsed: result.manaUsed,
|
|
557
|
+
ethPerFeeAsset: result.ethPerFeeAsset,
|
|
558
|
+
congestionCost: result.congestionCost,
|
|
559
|
+
proverCost: result.proverCost,
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
getEthPerFeeAsset(): Promise<bigint> {
|
|
564
|
+
return this.rollup.read.getEthPerFeeAsset();
|
|
447
565
|
}
|
|
448
566
|
|
|
449
567
|
async getCommitteeAt(timestamp: bigint): Promise<EthAddress[] | undefined> {
|
|
@@ -516,8 +634,9 @@ export class RollupContract {
|
|
|
516
634
|
return EthAddress.fromString(result);
|
|
517
635
|
}
|
|
518
636
|
|
|
519
|
-
async getCheckpoint(checkpointNumber: CheckpointNumber): Promise<CheckpointLog> {
|
|
520
|
-
|
|
637
|
+
async getCheckpoint(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise<CheckpointLog> {
|
|
638
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
639
|
+
const result = await this.rollup.read.getCheckpoint([BigInt(checkpointNumber)], options);
|
|
521
640
|
return {
|
|
522
641
|
archive: Fr.fromString(result.archive),
|
|
523
642
|
headerHash: Buffer32.fromString(result.headerHash),
|
|
@@ -528,7 +647,7 @@ export class RollupContract {
|
|
|
528
647
|
feeHeader: {
|
|
529
648
|
excessMana: result.feeHeader.excessMana,
|
|
530
649
|
manaUsed: result.feeHeader.manaUsed,
|
|
531
|
-
|
|
650
|
+
ethPerFeeAsset: result.feeHeader.ethPerFeeAsset,
|
|
532
651
|
congestionCost: result.feeHeader.congestionCost,
|
|
533
652
|
proverCost: result.feeHeader.proverCost,
|
|
534
653
|
},
|
|
@@ -550,6 +669,30 @@ export class RollupContract {
|
|
|
550
669
|
);
|
|
551
670
|
}
|
|
552
671
|
|
|
672
|
+
/**
|
|
673
|
+
* Returns the effective pending checkpoint, accounting for potential prunes.
|
|
674
|
+
* When a prune can happen, the L1 contract uses the proven checkpoint instead of the pending one.
|
|
675
|
+
* This mirrors the behavior of getEffectivePendingCheckpointNumber in STFLib.sol.
|
|
676
|
+
* @param atTimestamp - The timestamp to evaluate pruneability at. Defaults to the current L1 block timestamp.
|
|
677
|
+
* @param options - Optional L1 block number to pin the queries to.
|
|
678
|
+
*/
|
|
679
|
+
getEffectivePendingCheckpoint(atTimestamp?: bigint, options?: { blockNumber?: bigint }) {
|
|
680
|
+
return retry(
|
|
681
|
+
async () => {
|
|
682
|
+
const timestamp = atTimestamp ?? (await this.client.getBlock()).timestamp;
|
|
683
|
+
const canPrune = await this.canPruneAtTime(timestamp, options);
|
|
684
|
+
if (canPrune) {
|
|
685
|
+
const provenCheckpointNumber = await this.getProvenCheckpointNumber(options);
|
|
686
|
+
return await this.getCheckpoint(provenCheckpointNumber, options);
|
|
687
|
+
}
|
|
688
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber(options);
|
|
689
|
+
return await this.getCheckpoint(pendingCheckpointNumber, options);
|
|
690
|
+
},
|
|
691
|
+
'getting effective pending checkpoint',
|
|
692
|
+
makeBackoff([0.5, 0.5, 0.5]),
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
|
|
553
696
|
async getTips(): Promise<{ pending: CheckpointNumber; proven: CheckpointNumber }> {
|
|
554
697
|
const { pending, proven } = await this.rollup.read.getTips();
|
|
555
698
|
return {
|
|
@@ -668,14 +811,13 @@ export class RollupContract {
|
|
|
668
811
|
* timestamp of the next L1 block
|
|
669
812
|
* @throws otherwise
|
|
670
813
|
*/
|
|
671
|
-
public async
|
|
814
|
+
public async canProposeAt(
|
|
672
815
|
archive: Buffer,
|
|
673
816
|
account: `0x${string}` | Account,
|
|
674
|
-
|
|
675
|
-
|
|
817
|
+
timestamp: bigint,
|
|
818
|
+
stateOverride: StateOverride = [],
|
|
676
819
|
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
677
|
-
const
|
|
678
|
-
const timeOfNextL1Slot = latestBlock.timestamp + BigInt(slotDuration);
|
|
820
|
+
const timeOfNextL1Slot = timestamp;
|
|
679
821
|
const who = typeof account === 'string' ? account : account.address;
|
|
680
822
|
|
|
681
823
|
try {
|
|
@@ -687,7 +829,7 @@ export class RollupContract {
|
|
|
687
829
|
functionName: 'canProposeAtTime',
|
|
688
830
|
args: [timeOfNextL1Slot, `0x${archive.toString('hex')}`, who],
|
|
689
831
|
account,
|
|
690
|
-
stateOverride
|
|
832
|
+
stateOverride,
|
|
691
833
|
});
|
|
692
834
|
|
|
693
835
|
return {
|
|
@@ -723,6 +865,151 @@ export class RollupContract {
|
|
|
723
865
|
];
|
|
724
866
|
}
|
|
725
867
|
|
|
868
|
+
/**
|
|
869
|
+
* Returns a state override that sets tempCheckpointLogs[checkpointNumber].feeHeader to the compressed fee header.
|
|
870
|
+
* Used when simulating a propose call where the parent checkpoint hasn't landed on L1 yet (pipelining).
|
|
871
|
+
*/
|
|
872
|
+
public async makeFeeHeaderOverride(checkpointNumber: CheckpointNumber, feeHeader: FeeHeader): Promise<StateOverride> {
|
|
873
|
+
const { epochDuration, proofSubmissionEpochs } = await this.getRollupConstants();
|
|
874
|
+
const roundaboutSize = BigInt(epochDuration * (proofSubmissionEpochs + 1) + 1);
|
|
875
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
876
|
+
|
|
877
|
+
// tempCheckpointLogs is at offset 2 in RollupStore
|
|
878
|
+
const tempCheckpointLogsMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 2n;
|
|
879
|
+
|
|
880
|
+
// Solidity mapping slot: keccak256(abi.encode(key, baseSlot))
|
|
881
|
+
const structBaseSlot = hexToBigInt(
|
|
882
|
+
keccak256(
|
|
883
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsMappingBase]),
|
|
884
|
+
),
|
|
885
|
+
);
|
|
886
|
+
|
|
887
|
+
// feeHeader is the 7th field (offset 6) in CompressedTempCheckpointLog
|
|
888
|
+
const feeHeaderSlot = structBaseSlot + 6n;
|
|
889
|
+
const compressed = RollupContract.compressFeeHeader(feeHeader);
|
|
890
|
+
|
|
891
|
+
return [
|
|
892
|
+
{
|
|
893
|
+
address: this.address,
|
|
894
|
+
stateDiff: [
|
|
895
|
+
{
|
|
896
|
+
slot: `0x${feeHeaderSlot.toString(16).padStart(64, '0')}`,
|
|
897
|
+
value: `0x${compressed.toString(16).padStart(64, '0')}`,
|
|
898
|
+
},
|
|
899
|
+
],
|
|
900
|
+
},
|
|
901
|
+
];
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Returns a state override that sets archives[checkpointNumber] to the given archive value.
|
|
906
|
+
* Used when simulating a canProposeAtTime call where the local archive differs from L1
|
|
907
|
+
* (e.g. pipelining where the parent checkpoint hasn't landed on L1 yet).
|
|
908
|
+
*/
|
|
909
|
+
public makeArchiveOverride(checkpointNumber: CheckpointNumber, archive: Fr): StateOverride {
|
|
910
|
+
const archivesMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 1n;
|
|
911
|
+
const archiveSlot = hexToBigInt(
|
|
912
|
+
keccak256(
|
|
913
|
+
encodeAbiParameters(
|
|
914
|
+
[{ type: 'uint256' }, { type: 'uint256' }],
|
|
915
|
+
[BigInt(checkpointNumber), archivesMappingBase],
|
|
916
|
+
),
|
|
917
|
+
),
|
|
918
|
+
);
|
|
919
|
+
return [
|
|
920
|
+
{
|
|
921
|
+
address: this.address,
|
|
922
|
+
stateDiff: [
|
|
923
|
+
{
|
|
924
|
+
slot: `0x${archiveSlot.toString(16).padStart(64, '0')}`,
|
|
925
|
+
value: archive.toString(),
|
|
926
|
+
},
|
|
927
|
+
],
|
|
928
|
+
},
|
|
929
|
+
];
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/** Merges multiple StateOverride arrays, combining stateDiff entries for the same address. */
|
|
933
|
+
public static mergeStateOverrides(...overrides: StateOverride[]): StateOverride {
|
|
934
|
+
type StateDiffEntry = { slot: `0x${string}`; value: `0x${string}` };
|
|
935
|
+
const byAddress = new Map<string, { address: `0x${string}`; balance?: bigint; stateDiff: StateDiffEntry[] }>();
|
|
936
|
+
for (const override of overrides) {
|
|
937
|
+
for (const entry of override) {
|
|
938
|
+
const key = entry.address.toLowerCase();
|
|
939
|
+
const existing = byAddress.get(key);
|
|
940
|
+
if (existing) {
|
|
941
|
+
existing.stateDiff.push(...(entry.stateDiff ?? []));
|
|
942
|
+
if (entry.balance !== undefined) {
|
|
943
|
+
existing.balance = entry.balance;
|
|
944
|
+
}
|
|
945
|
+
} else {
|
|
946
|
+
byAddress.set(key, {
|
|
947
|
+
address: entry.address,
|
|
948
|
+
balance: entry.balance,
|
|
949
|
+
stateDiff: [...(entry.stateDiff ?? [])],
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
return [...byAddress.values()];
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/** Compresses a FeeHeader into a uint256 matching FeeHeaderLib.compress() in FeeStructs.sol. */
|
|
958
|
+
public static compressFeeHeader(feeHeader: FeeHeader): bigint {
|
|
959
|
+
const MASK_48_BITS = (1n << 48n) - 1n;
|
|
960
|
+
const MASK_64_BITS = (1n << 64n) - 1n;
|
|
961
|
+
const MASK_63_BITS = (1n << 63n) - 1n;
|
|
962
|
+
|
|
963
|
+
let value = BigInt(feeHeader.manaUsed) & ((1n << 32n) - 1n); // bits [0:31]
|
|
964
|
+
value |= (feeHeader.excessMana < MASK_48_BITS ? feeHeader.excessMana : MASK_48_BITS) << 32n; // bits [32:79]
|
|
965
|
+
value |= (BigInt(feeHeader.ethPerFeeAsset) & MASK_48_BITS) << 80n; // bits [80:127]
|
|
966
|
+
value |= (feeHeader.congestionCost < MASK_64_BITS ? feeHeader.congestionCost : MASK_64_BITS) << 128n; // bits [128:191]
|
|
967
|
+
value |= (feeHeader.proverCost < MASK_63_BITS ? feeHeader.proverCost : MASK_63_BITS) << 192n; // bits [192:254]
|
|
968
|
+
value |= 1n << 255n; // preheat flag
|
|
969
|
+
return value;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/** Computes the fee header for a child checkpoint given parent fee header and child data.
|
|
973
|
+
* Must stay in sync with Solidity FeeLib.sol (computeNewEthPerFeeAsset, clampedAdd). */
|
|
974
|
+
public static computeChildFeeHeader(
|
|
975
|
+
parentFeeHeader: FeeHeader,
|
|
976
|
+
childManaUsed: bigint,
|
|
977
|
+
feeAssetPriceModifier: bigint,
|
|
978
|
+
manaTarget: bigint,
|
|
979
|
+
): FeeHeader {
|
|
980
|
+
const MIN_ETH_PER_FEE_ASSET = 100n;
|
|
981
|
+
const MAX_ETH_PER_FEE_ASSET = 100_000_000_000_000n; // 1e14, matches FeeLib.sol
|
|
982
|
+
|
|
983
|
+
// excessMana = clampedAdd(parent.excessMana + parent.manaUsed, -manaTarget)
|
|
984
|
+
const sum = parentFeeHeader.excessMana + parentFeeHeader.manaUsed;
|
|
985
|
+
const excessMana = sum > manaTarget ? sum - manaTarget : 0n;
|
|
986
|
+
|
|
987
|
+
// ethPerFeeAsset = computeNewEthPerFeeAsset(max(parent.ethPerFeeAsset, MIN), modifier)
|
|
988
|
+
const parentPrice =
|
|
989
|
+
parentFeeHeader.ethPerFeeAsset > MIN_ETH_PER_FEE_ASSET ? parentFeeHeader.ethPerFeeAsset : MIN_ETH_PER_FEE_ASSET;
|
|
990
|
+
let newPrice: bigint;
|
|
991
|
+
if (feeAssetPriceModifier >= 0n) {
|
|
992
|
+
newPrice = (parentPrice * (10_000n + feeAssetPriceModifier)) / 10_000n;
|
|
993
|
+
} else {
|
|
994
|
+
const absMod = -feeAssetPriceModifier;
|
|
995
|
+
newPrice = (parentPrice * (10_000n - absMod)) / 10_000n;
|
|
996
|
+
}
|
|
997
|
+
if (newPrice < MIN_ETH_PER_FEE_ASSET) {
|
|
998
|
+
newPrice = MIN_ETH_PER_FEE_ASSET;
|
|
999
|
+
}
|
|
1000
|
+
if (newPrice > MAX_ETH_PER_FEE_ASSET) {
|
|
1001
|
+
newPrice = MAX_ETH_PER_FEE_ASSET;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
return {
|
|
1005
|
+
excessMana,
|
|
1006
|
+
manaUsed: childManaUsed,
|
|
1007
|
+
ethPerFeeAsset: newPrice,
|
|
1008
|
+
congestionCost: 0n,
|
|
1009
|
+
proverCost: 0n,
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
|
|
726
1013
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
727
1014
|
public buildInvalidateBadAttestationRequest(
|
|
728
1015
|
checkpointNumber: CheckpointNumber,
|
|
@@ -732,6 +1019,7 @@ export class RollupContract {
|
|
|
732
1019
|
): L1TxRequest {
|
|
733
1020
|
return {
|
|
734
1021
|
to: this.address,
|
|
1022
|
+
abi: RollupAbi,
|
|
735
1023
|
data: encodeFunctionData({
|
|
736
1024
|
abi: RollupAbi,
|
|
737
1025
|
functionName: 'invalidateBadAttestation',
|
|
@@ -753,6 +1041,7 @@ export class RollupContract {
|
|
|
753
1041
|
): L1TxRequest {
|
|
754
1042
|
return {
|
|
755
1043
|
to: this.address,
|
|
1044
|
+
abi: RollupAbi,
|
|
756
1045
|
data: encodeFunctionData({
|
|
757
1046
|
abi: RollupAbi,
|
|
758
1047
|
functionName: 'invalidateInsufficientAttestations',
|
|
@@ -769,8 +1058,18 @@ export class RollupContract {
|
|
|
769
1058
|
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]);
|
|
770
1059
|
}
|
|
771
1060
|
|
|
772
|
-
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean): Promise<bigint> {
|
|
773
|
-
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset]);
|
|
1061
|
+
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean, stateOverride?: StateOverride): Promise<bigint> {
|
|
1062
|
+
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset], { stateOverride });
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
async getManaMinFeeComponentsAt(timestamp: bigint, inFeeAsset: boolean): Promise<ManaMinFeeComponents> {
|
|
1066
|
+
const result = await this.rollup.read.getManaMinFeeComponentsAt([timestamp, inFeeAsset]);
|
|
1067
|
+
return {
|
|
1068
|
+
sequencerCost: result.sequencerCost,
|
|
1069
|
+
proverCost: result.proverCost,
|
|
1070
|
+
congestionCost: result.congestionCost,
|
|
1071
|
+
congestionMultiplier: result.congestionMultiplier,
|
|
1072
|
+
};
|
|
774
1073
|
}
|
|
775
1074
|
|
|
776
1075
|
async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
|
|
@@ -816,11 +1115,10 @@ export class RollupContract {
|
|
|
816
1115
|
return this.rollup.read.getSpecificProverRewardsForEpoch([epoch, prover]);
|
|
817
1116
|
}
|
|
818
1117
|
|
|
819
|
-
async getAttesters(): Promise<EthAddress[]> {
|
|
1118
|
+
async getAttesters(timestamp?: bigint): Promise<EthAddress[]> {
|
|
820
1119
|
const attesterSize = await this.getActiveAttesterCount();
|
|
821
1120
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
822
|
-
const ts = (await this.client.getBlock()).timestamp;
|
|
823
|
-
|
|
1121
|
+
const ts = timestamp ?? (await this.client.getBlock()).timestamp;
|
|
824
1122
|
const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i));
|
|
825
1123
|
const chunks = chunk(indices, 1000);
|
|
826
1124
|
|
|
@@ -886,6 +1184,7 @@ export class RollupContract {
|
|
|
886
1184
|
setupEpoch(l1TxUtils: L1TxUtils) {
|
|
887
1185
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
888
1186
|
to: this.address,
|
|
1187
|
+
abi: RollupAbi,
|
|
889
1188
|
data: encodeFunctionData({
|
|
890
1189
|
abi: RollupAbi,
|
|
891
1190
|
functionName: 'setupEpoch',
|
|
@@ -897,6 +1196,7 @@ export class RollupContract {
|
|
|
897
1196
|
vote(l1TxUtils: L1TxUtils, proposalId: bigint) {
|
|
898
1197
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
899
1198
|
to: this.address,
|
|
1199
|
+
abi: RollupAbi,
|
|
900
1200
|
data: encodeFunctionData({
|
|
901
1201
|
abi: RollupAbi,
|
|
902
1202
|
functionName: 'vote',
|
|
@@ -965,4 +1265,72 @@ export class RollupContract {
|
|
|
965
1265
|
},
|
|
966
1266
|
);
|
|
967
1267
|
}
|
|
1268
|
+
|
|
1269
|
+
/** Fetches CheckpointProposed events within the given block range. */
|
|
1270
|
+
async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
|
|
1271
|
+
const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
|
|
1272
|
+
return logs
|
|
1273
|
+
.filter(log => log.blockNumber! >= fromBlock && log.blockNumber! <= toBlock)
|
|
1274
|
+
.map(log => ({
|
|
1275
|
+
l1BlockNumber: log.blockNumber!,
|
|
1276
|
+
l1BlockHash: Buffer32.fromString(log.blockHash!),
|
|
1277
|
+
l1TransactionHash: log.transactionHash!,
|
|
1278
|
+
args: {
|
|
1279
|
+
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
1280
|
+
archive: Fr.fromString(log.args.archive!),
|
|
1281
|
+
versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
|
|
1282
|
+
attestationsHash: (() => {
|
|
1283
|
+
if (!log.args.attestationsHash) {
|
|
1284
|
+
throw new Error(
|
|
1285
|
+
`CheckpointProposed event missing attestationsHash for checkpoint ${log.args.checkpointNumber}`,
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
return Buffer32.fromString(log.args.attestationsHash);
|
|
1289
|
+
})(),
|
|
1290
|
+
payloadDigest: (() => {
|
|
1291
|
+
if (!log.args.payloadDigest) {
|
|
1292
|
+
throw new Error(
|
|
1293
|
+
`CheckpointProposed event missing payloadDigest for checkpoint ${log.args.checkpointNumber}`,
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
return Buffer32.fromString(log.args.payloadDigest);
|
|
1297
|
+
})(),
|
|
1298
|
+
},
|
|
1299
|
+
}));
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
/** Packs pending and proven checkpoint numbers into the chain tips storage format. */
|
|
1303
|
+
static packChainTips(pendingCheckpointNumber: bigint, provenCheckpointNumber: bigint): bigint {
|
|
1304
|
+
return (pendingCheckpointNumber << 128n) | (provenCheckpointNumber & ((1n << 128n) - 1n));
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
/** Storage slot for the chain tips (offset 0 within the STF storage struct). */
|
|
1308
|
+
static get chainTipsStorageSlot(): bigint {
|
|
1309
|
+
return BigInt(RollupContract.stfStorageSlot);
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
/**
|
|
1313
|
+
* Computes the storage slot for a field within a tempCheckpointLog entry.
|
|
1314
|
+
* @param checkpointNumber - The checkpoint number
|
|
1315
|
+
* @param field - The field within the CompressedTempCheckpointLog struct
|
|
1316
|
+
*/
|
|
1317
|
+
async getTempCheckpointLogStorageSlot(
|
|
1318
|
+
checkpointNumber: CheckpointNumber,
|
|
1319
|
+
field: TempCheckpointLogField,
|
|
1320
|
+
): Promise<bigint> {
|
|
1321
|
+
const fieldOffset = BigInt(field);
|
|
1322
|
+
const [epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
1323
|
+
this.getEpochDuration(),
|
|
1324
|
+
this.getProofSubmissionEpochs(),
|
|
1325
|
+
]);
|
|
1326
|
+
const roundaboutSize = BigInt(epochDuration) * (BigInt(proofSubmissionEpochs) + 1n) + 1n;
|
|
1327
|
+
const tempCheckpointLogsBase = BigInt(RollupContract.stfStorageSlot) + 2n;
|
|
1328
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
1329
|
+
const entryBase = BigInt(
|
|
1330
|
+
keccak256(
|
|
1331
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsBase]),
|
|
1332
|
+
),
|
|
1333
|
+
);
|
|
1334
|
+
return entryBase + fieldOffset;
|
|
1335
|
+
}
|
|
968
1336
|
}
|