@aztec/ethereum 0.0.1-commit.9372f48 → 0.0.1-commit.949a33fd8
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 +16 -2
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +27 -7
- package/dest/config.d.ts +8 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +15 -11
- 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_price_oracle.d.ts +101 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
- package/dest/contracts/fee_asset_price_oracle.js +651 -0
- package/dest/contracts/governance.js +3 -3
- package/dest/contracts/governance_proposer.d.ts +3 -1
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +9 -0
- package/dest/contracts/inbox.d.ts +3 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +11 -6
- package/dest/contracts/index.d.ts +4 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +3 -2
- package/dest/contracts/multicall.d.ts +51 -2
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +85 -0
- package/dest/contracts/registry.d.ts +3 -1
- package/dest/contracts/registry.d.ts.map +1 -1
- package/dest/contracts/registry.js +30 -1
- package/dest/contracts/rollup.d.ts +5015 -25
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +316 -61
- 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 +4 -8
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +39 -26
- package/dest/deploy_l1_contract.js +3 -3
- package/dest/generated/l1-contracts-defaults.d.ts +2 -2
- package/dest/generated/l1-contracts-defaults.js +2 -2
- package/dest/l1_artifacts.d.ts +9404 -15792
- 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 +7 -2
- package/dest/l1_tx_utils/config.d.ts +7 -1
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +14 -1
- package/dest/l1_tx_utils/factory.d.ts +18 -10
- package/dest/l1_tx_utils/factory.d.ts.map +1 -1
- package/dest/l1_tx_utils/factory.js +17 -7
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +1 -1
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +1 -1
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +15 -15
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +9 -15
- package/dest/l1_tx_utils/index-blobs.d.ts +3 -3
- package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -1
- package/dest/l1_tx_utils/index-blobs.js +2 -2
- package/dest/l1_tx_utils/index.d.ts +2 -1
- package/dest/l1_tx_utils/index.d.ts.map +1 -1
- package/dest/l1_tx_utils/index.js +1 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +20 -7
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +75 -51
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +8 -4
- package/dest/l1_tx_utils/tx_delayer.d.ts +56 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
- package/dest/{test → l1_tx_utils}/tx_delayer.js +62 -34
- package/dest/publisher_manager.d.ts +21 -7
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +81 -7
- package/dest/queries.d.ts +13 -2
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +62 -3
- package/dest/test/chain_monitor.d.ts +23 -3
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +38 -2
- package/dest/test/eth_cheat_codes.d.ts +6 -4
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +6 -4
- package/dest/test/index.d.ts +1 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +0 -2
- package/dest/test/rollup_cheat_codes.d.ts +5 -1
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +9 -1
- package/dest/test/start_anvil.d.ts +23 -3
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +143 -29
- package/dest/test/upgrade_utils.js +2 -2
- package/dest/utils.d.ts +1 -1
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +16 -12
- package/package.json +5 -7
- package/src/client.ts +28 -2
- package/src/config.ts +24 -15
- package/src/contracts/chain_state_override.ts +147 -0
- package/src/contracts/empire_base.ts +2 -0
- package/src/contracts/fee_asset_price_oracle.ts +280 -0
- package/src/contracts/governance.ts +3 -3
- package/src/contracts/governance_proposer.ts +6 -0
- package/src/contracts/inbox.ts +12 -4
- package/src/contracts/index.ts +3 -2
- package/src/contracts/multicall.ts +65 -1
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +345 -61
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +14 -16
- package/src/deploy_aztec_l1_contracts.ts +61 -34
- package/src/deploy_l1_contract.ts +3 -3
- package/src/generated/l1-contracts-defaults.ts +2 -2
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +0 -7
- package/src/l1_reader.ts +14 -2
- package/src/l1_tx_utils/config.ts +20 -0
- package/src/l1_tx_utils/factory.ts +31 -31
- package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +1 -1
- package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +1 -1
- package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +43 -54
- package/src/l1_tx_utils/index-blobs.ts +2 -2
- package/src/l1_tx_utils/index.ts +1 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +68 -30
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +8 -4
- package/src/{test → l1_tx_utils}/tx_delayer.ts +78 -50
- package/src/publisher_manager.ts +105 -10
- package/src/queries.ts +70 -4
- package/src/test/chain_monitor.ts +65 -3
- package/src/test/eth_cheat_codes.ts +6 -4
- package/src/test/index.ts +0 -2
- package/src/test/rollup_cheat_codes.ts +11 -1
- package/src/test/start_anvil.ts +177 -29
- package/src/test/upgrade_utils.ts +2 -2
- package/src/utils.ts +17 -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 -207
- 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 -259
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
- package/src/test/delayed_tx_utils.ts +0 -52
package/src/contracts/rollup.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
4
4
|
import { memoize } from '@aztec/foundation/decorators';
|
|
5
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
6
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
7
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
7
8
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
8
9
|
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
9
10
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
@@ -14,8 +15,10 @@ import {
|
|
|
14
15
|
type Account,
|
|
15
16
|
type GetContractReturnType,
|
|
16
17
|
type Hex,
|
|
18
|
+
type Log,
|
|
17
19
|
type StateOverride,
|
|
18
20
|
type WatchContractEventReturnType,
|
|
21
|
+
encodeAbiParameters,
|
|
19
22
|
encodeFunctionData,
|
|
20
23
|
getContract,
|
|
21
24
|
hexToBigInt,
|
|
@@ -29,11 +32,10 @@ import type { L1ReaderConfig } from '../l1_reader.js';
|
|
|
29
32
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
30
33
|
import type { ViemClient } from '../types.js';
|
|
31
34
|
import { formatViemError } from '../utils.js';
|
|
32
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
33
35
|
import { GSEContract } from './gse.js';
|
|
34
36
|
import type { L1EventLog } from './log.js';
|
|
35
37
|
import { SlasherContract } from './slasher_contract.js';
|
|
36
|
-
import {
|
|
38
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
37
39
|
import { checkBlockTag } from './utils.js';
|
|
38
40
|
|
|
39
41
|
export type ViemCommitteeAttestation = {
|
|
@@ -55,7 +57,6 @@ export type L1RollupContractAddresses = Pick<
|
|
|
55
57
|
| 'feeJuiceAddress'
|
|
56
58
|
| 'stakingAssetAddress'
|
|
57
59
|
| 'rewardDistributorAddress'
|
|
58
|
-
| 'slashFactoryAddress'
|
|
59
60
|
| 'gseAddress'
|
|
60
61
|
>;
|
|
61
62
|
|
|
@@ -85,12 +86,6 @@ export type ViemGasFees = {
|
|
|
85
86
|
feePerL2Gas: bigint;
|
|
86
87
|
};
|
|
87
88
|
|
|
88
|
-
export enum SlashingProposerType {
|
|
89
|
-
None = 0,
|
|
90
|
-
Tally = 1,
|
|
91
|
-
Empire = 2,
|
|
92
|
-
}
|
|
93
|
-
|
|
94
89
|
/**
|
|
95
90
|
* Status of a validator/attester in the staking system.
|
|
96
91
|
* Matches the Status enum in StakingLib.sol
|
|
@@ -134,6 +129,25 @@ export type L1FeeData = {
|
|
|
134
129
|
blobFee: bigint;
|
|
135
130
|
};
|
|
136
131
|
|
|
132
|
+
/** Field offsets within the CompressedTempCheckpointLog struct in Solidity storage. */
|
|
133
|
+
export enum TempCheckpointLogField {
|
|
134
|
+
HeaderHash = 0,
|
|
135
|
+
BlobCommitmentsHash = 1,
|
|
136
|
+
OutHash = 2,
|
|
137
|
+
AttestationsHash = 3,
|
|
138
|
+
PayloadDigest = 4,
|
|
139
|
+
SlotNumber = 5,
|
|
140
|
+
FeeHeader = 6,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
|
|
144
|
+
export type ManaMinFeeComponents = {
|
|
145
|
+
sequencerCost: bigint;
|
|
146
|
+
proverCost: bigint;
|
|
147
|
+
congestionCost: bigint;
|
|
148
|
+
congestionMultiplier: bigint;
|
|
149
|
+
};
|
|
150
|
+
|
|
137
151
|
/**
|
|
138
152
|
* Reward configuration for the rollup
|
|
139
153
|
*/
|
|
@@ -193,10 +207,10 @@ export type CheckpointProposedArgs = {
|
|
|
193
207
|
checkpointNumber: CheckpointNumber;
|
|
194
208
|
archive: Fr;
|
|
195
209
|
versionedBlobHashes: Buffer[];
|
|
196
|
-
/** Hash of attestations
|
|
197
|
-
attestationsHash
|
|
198
|
-
/** Digest of the payload
|
|
199
|
-
payloadDigest
|
|
210
|
+
/** Hash of attestations emitted in the CheckpointProposed event. */
|
|
211
|
+
attestationsHash: Buffer32;
|
|
212
|
+
/** Digest of the payload emitted in the CheckpointProposed event. */
|
|
213
|
+
payloadDigest: Buffer32;
|
|
200
214
|
};
|
|
201
215
|
|
|
202
216
|
/** Log type for CheckpointProposed events. */
|
|
@@ -204,6 +218,7 @@ export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
|
204
218
|
|
|
205
219
|
export class RollupContract {
|
|
206
220
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
221
|
+
private readonly logger = createLogger('ethereum:rollup');
|
|
207
222
|
|
|
208
223
|
private static cachedStfStorageSlot: Hex | undefined;
|
|
209
224
|
private cachedEscapeHatch?: {
|
|
@@ -259,34 +274,18 @@ export class RollupContract {
|
|
|
259
274
|
return this.rollup;
|
|
260
275
|
}
|
|
261
276
|
|
|
262
|
-
public async getSlashingProposer(): Promise<
|
|
263
|
-
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
264
|
-
> {
|
|
277
|
+
public async getSlashingProposer(): Promise<SlashingProposerContract | undefined> {
|
|
265
278
|
const slasher = await this.getSlasherContract();
|
|
266
279
|
if (!slasher) {
|
|
267
280
|
return undefined;
|
|
268
281
|
}
|
|
269
282
|
|
|
270
283
|
const proposerAddress = await slasher.getProposer();
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
type: 'function',
|
|
274
|
-
name: 'SLASHING_PROPOSER_TYPE',
|
|
275
|
-
inputs: [],
|
|
276
|
-
outputs: [{ name: '', type: 'uint8', internalType: 'enum SlasherFlavor' }],
|
|
277
|
-
stateMutability: 'view',
|
|
278
|
-
},
|
|
279
|
-
] as const;
|
|
280
|
-
|
|
281
|
-
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
|
|
282
|
-
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
283
|
-
if (proposerType === SlashingProposerType.Tally.valueOf()) {
|
|
284
|
-
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
285
|
-
} else if (proposerType === SlashingProposerType.Empire.valueOf()) {
|
|
286
|
-
return new EmpireSlashingProposerContract(this.client, proposerAddress);
|
|
287
|
-
} else {
|
|
288
|
-
throw new Error(`Unknown slashing proposer type: ${proposerType}`);
|
|
284
|
+
if (proposerAddress.isZero()) {
|
|
285
|
+
return undefined;
|
|
289
286
|
}
|
|
287
|
+
|
|
288
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
290
289
|
}
|
|
291
290
|
|
|
292
291
|
@memoize
|
|
@@ -379,6 +378,20 @@ export class RollupContract {
|
|
|
379
378
|
return Fr.fromString(await this.rollup.read.archiveAt([0n]));
|
|
380
379
|
}
|
|
381
380
|
|
|
381
|
+
@memoize
|
|
382
|
+
async getVkTreeRoot(): Promise<Fr> {
|
|
383
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 3n;
|
|
384
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
385
|
+
return Fr.fromString(value ?? '0x0');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
@memoize
|
|
389
|
+
async getProtocolContractsHash(): Promise<Fr> {
|
|
390
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 4n;
|
|
391
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
392
|
+
return Fr.fromString(value ?? '0x0');
|
|
393
|
+
}
|
|
394
|
+
|
|
382
395
|
/**
|
|
383
396
|
* Returns rollup constants used for epoch queries.
|
|
384
397
|
* Return type is `L1RollupConstants` which is defined in stdlib,
|
|
@@ -391,13 +404,25 @@ export class RollupContract {
|
|
|
391
404
|
slotDuration: number;
|
|
392
405
|
epochDuration: number;
|
|
393
406
|
proofSubmissionEpochs: number;
|
|
407
|
+
targetCommitteeSize: number;
|
|
408
|
+
rollupManaLimit: number;
|
|
394
409
|
}> {
|
|
395
|
-
const [
|
|
410
|
+
const [
|
|
411
|
+
l1StartBlock,
|
|
412
|
+
l1GenesisTime,
|
|
413
|
+
slotDuration,
|
|
414
|
+
epochDuration,
|
|
415
|
+
proofSubmissionEpochs,
|
|
416
|
+
targetCommitteeSize,
|
|
417
|
+
rollupManaLimit,
|
|
418
|
+
] = await Promise.all([
|
|
396
419
|
this.getL1StartBlock(),
|
|
397
420
|
this.getL1GenesisTime(),
|
|
398
421
|
this.getSlotDuration(),
|
|
399
422
|
this.getEpochDuration(),
|
|
400
423
|
this.getProofSubmissionEpochs(),
|
|
424
|
+
this.getTargetCommitteeSize(),
|
|
425
|
+
this.getManaLimit(),
|
|
401
426
|
]);
|
|
402
427
|
return {
|
|
403
428
|
l1StartBlock,
|
|
@@ -405,6 +430,8 @@ export class RollupContract {
|
|
|
405
430
|
slotDuration,
|
|
406
431
|
epochDuration: Number(epochDuration),
|
|
407
432
|
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
433
|
+
targetCommitteeSize,
|
|
434
|
+
rollupManaLimit: Number(rollupManaLimit),
|
|
408
435
|
};
|
|
409
436
|
}
|
|
410
437
|
|
|
@@ -459,7 +486,11 @@ export class RollupContract {
|
|
|
459
486
|
|
|
460
487
|
const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
|
|
461
488
|
return isOpen;
|
|
462
|
-
} catch {
|
|
489
|
+
} catch (err) {
|
|
490
|
+
this.logger.warn('isEscapeHatchOpen failed (treating as closed); RPC or contract error may cause liveness risk', {
|
|
491
|
+
epoch: Number(epoch),
|
|
492
|
+
error: err,
|
|
493
|
+
});
|
|
463
494
|
return false;
|
|
464
495
|
}
|
|
465
496
|
}
|
|
@@ -495,26 +526,41 @@ export class RollupContract {
|
|
|
495
526
|
return this.rollup.read.getCheckpointReward();
|
|
496
527
|
}
|
|
497
528
|
|
|
498
|
-
async getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
499
|
-
|
|
529
|
+
async getCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
530
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
531
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber(options));
|
|
500
532
|
}
|
|
501
533
|
|
|
502
|
-
async getProvenCheckpointNumber(): Promise<CheckpointNumber> {
|
|
503
|
-
|
|
534
|
+
async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
535
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
536
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
504
537
|
}
|
|
505
538
|
|
|
506
|
-
async getSlotNumber(): Promise<SlotNumber> {
|
|
507
|
-
|
|
539
|
+
async getSlotNumber(options?: { blockNumber?: bigint }): Promise<SlotNumber> {
|
|
540
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
541
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot(options));
|
|
508
542
|
}
|
|
509
543
|
|
|
510
|
-
async getL1FeesAt(timestamp: bigint): Promise<L1FeeData> {
|
|
511
|
-
|
|
544
|
+
async getL1FeesAt(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<L1FeeData> {
|
|
545
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
546
|
+
const result = await this.rollup.read.getL1FeesAt([timestamp], options);
|
|
512
547
|
return {
|
|
513
548
|
baseFee: result.baseFee,
|
|
514
549
|
blobFee: result.blobFee,
|
|
515
550
|
};
|
|
516
551
|
}
|
|
517
552
|
|
|
553
|
+
async getFeeHeader(checkpointNumber: bigint): Promise<FeeHeader> {
|
|
554
|
+
const result = await this.rollup.read.getFeeHeader([checkpointNumber]);
|
|
555
|
+
return {
|
|
556
|
+
excessMana: result.excessMana,
|
|
557
|
+
manaUsed: result.manaUsed,
|
|
558
|
+
ethPerFeeAsset: result.ethPerFeeAsset,
|
|
559
|
+
congestionCost: result.congestionCost,
|
|
560
|
+
proverCost: result.proverCost,
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
518
564
|
getEthPerFeeAsset(): Promise<bigint> {
|
|
519
565
|
return this.rollup.read.getEthPerFeeAsset();
|
|
520
566
|
}
|
|
@@ -589,8 +635,9 @@ export class RollupContract {
|
|
|
589
635
|
return EthAddress.fromString(result);
|
|
590
636
|
}
|
|
591
637
|
|
|
592
|
-
async getCheckpoint(checkpointNumber: CheckpointNumber): Promise<CheckpointLog> {
|
|
593
|
-
|
|
638
|
+
async getCheckpoint(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise<CheckpointLog> {
|
|
639
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
640
|
+
const result = await this.rollup.read.getCheckpoint([BigInt(checkpointNumber)], options);
|
|
594
641
|
return {
|
|
595
642
|
archive: Fr.fromString(result.archive),
|
|
596
643
|
headerHash: Buffer32.fromString(result.headerHash),
|
|
@@ -623,6 +670,30 @@ export class RollupContract {
|
|
|
623
670
|
);
|
|
624
671
|
}
|
|
625
672
|
|
|
673
|
+
/**
|
|
674
|
+
* Returns the effective pending checkpoint, accounting for potential prunes.
|
|
675
|
+
* When a prune can happen, the L1 contract uses the proven checkpoint instead of the pending one.
|
|
676
|
+
* This mirrors the behavior of getEffectivePendingCheckpointNumber in STFLib.sol.
|
|
677
|
+
* @param atTimestamp - The timestamp to evaluate pruneability at. Defaults to the current L1 block timestamp.
|
|
678
|
+
* @param options - Optional L1 block number to pin the queries to.
|
|
679
|
+
*/
|
|
680
|
+
getEffectivePendingCheckpoint(atTimestamp?: bigint, options?: { blockNumber?: bigint }) {
|
|
681
|
+
return retry(
|
|
682
|
+
async () => {
|
|
683
|
+
const timestamp = atTimestamp ?? (await this.client.getBlock()).timestamp;
|
|
684
|
+
const canPrune = await this.canPruneAtTime(timestamp, options);
|
|
685
|
+
if (canPrune) {
|
|
686
|
+
const provenCheckpointNumber = await this.getProvenCheckpointNumber(options);
|
|
687
|
+
return await this.getCheckpoint(provenCheckpointNumber, options);
|
|
688
|
+
}
|
|
689
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber(options);
|
|
690
|
+
return await this.getCheckpoint(pendingCheckpointNumber, options);
|
|
691
|
+
},
|
|
692
|
+
'getting effective pending checkpoint',
|
|
693
|
+
makeBackoff([0.5, 0.5, 0.5]),
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
|
|
626
697
|
async getTips(): Promise<{ pending: CheckpointNumber; proven: CheckpointNumber }> {
|
|
627
698
|
const { pending, proven } = await this.rollup.read.getTips();
|
|
628
699
|
return {
|
|
@@ -741,14 +812,13 @@ export class RollupContract {
|
|
|
741
812
|
* timestamp of the next L1 block
|
|
742
813
|
* @throws otherwise
|
|
743
814
|
*/
|
|
744
|
-
public async
|
|
815
|
+
public async canProposeAt(
|
|
745
816
|
archive: Buffer,
|
|
746
817
|
account: `0x${string}` | Account,
|
|
747
|
-
|
|
748
|
-
|
|
818
|
+
timestamp: bigint,
|
|
819
|
+
stateOverride: StateOverride = [],
|
|
749
820
|
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
750
|
-
const
|
|
751
|
-
const timeOfNextL1Slot = latestBlock.timestamp + BigInt(slotDuration);
|
|
821
|
+
const timeOfNextL1Slot = timestamp;
|
|
752
822
|
const who = typeof account === 'string' ? account : account.address;
|
|
753
823
|
|
|
754
824
|
try {
|
|
@@ -760,7 +830,7 @@ export class RollupContract {
|
|
|
760
830
|
functionName: 'canProposeAtTime',
|
|
761
831
|
args: [timeOfNextL1Slot, `0x${archive.toString('hex')}`, who],
|
|
762
832
|
account,
|
|
763
|
-
stateOverride
|
|
833
|
+
stateOverride,
|
|
764
834
|
});
|
|
765
835
|
|
|
766
836
|
return {
|
|
@@ -796,6 +866,151 @@ export class RollupContract {
|
|
|
796
866
|
];
|
|
797
867
|
}
|
|
798
868
|
|
|
869
|
+
/**
|
|
870
|
+
* Returns a state override that sets tempCheckpointLogs[checkpointNumber].feeHeader to the compressed fee header.
|
|
871
|
+
* Used when simulating a propose call where the parent checkpoint hasn't landed on L1 yet (pipelining).
|
|
872
|
+
*/
|
|
873
|
+
public async makeFeeHeaderOverride(checkpointNumber: CheckpointNumber, feeHeader: FeeHeader): Promise<StateOverride> {
|
|
874
|
+
const { epochDuration, proofSubmissionEpochs } = await this.getRollupConstants();
|
|
875
|
+
const roundaboutSize = BigInt(epochDuration * (proofSubmissionEpochs + 1) + 1);
|
|
876
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
877
|
+
|
|
878
|
+
// tempCheckpointLogs is at offset 2 in RollupStore
|
|
879
|
+
const tempCheckpointLogsMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 2n;
|
|
880
|
+
|
|
881
|
+
// Solidity mapping slot: keccak256(abi.encode(key, baseSlot))
|
|
882
|
+
const structBaseSlot = hexToBigInt(
|
|
883
|
+
keccak256(
|
|
884
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsMappingBase]),
|
|
885
|
+
),
|
|
886
|
+
);
|
|
887
|
+
|
|
888
|
+
// feeHeader is the 7th field (offset 6) in CompressedTempCheckpointLog
|
|
889
|
+
const feeHeaderSlot = structBaseSlot + 6n;
|
|
890
|
+
const compressed = RollupContract.compressFeeHeader(feeHeader);
|
|
891
|
+
|
|
892
|
+
return [
|
|
893
|
+
{
|
|
894
|
+
address: this.address,
|
|
895
|
+
stateDiff: [
|
|
896
|
+
{
|
|
897
|
+
slot: `0x${feeHeaderSlot.toString(16).padStart(64, '0')}`,
|
|
898
|
+
value: `0x${compressed.toString(16).padStart(64, '0')}`,
|
|
899
|
+
},
|
|
900
|
+
],
|
|
901
|
+
},
|
|
902
|
+
];
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* Returns a state override that sets archives[checkpointNumber] to the given archive value.
|
|
907
|
+
* Used when simulating a canProposeAtTime call where the local archive differs from L1
|
|
908
|
+
* (e.g. pipelining where the parent checkpoint hasn't landed on L1 yet).
|
|
909
|
+
*/
|
|
910
|
+
public makeArchiveOverride(checkpointNumber: CheckpointNumber, archive: Fr): StateOverride {
|
|
911
|
+
const archivesMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 1n;
|
|
912
|
+
const archiveSlot = hexToBigInt(
|
|
913
|
+
keccak256(
|
|
914
|
+
encodeAbiParameters(
|
|
915
|
+
[{ type: 'uint256' }, { type: 'uint256' }],
|
|
916
|
+
[BigInt(checkpointNumber), archivesMappingBase],
|
|
917
|
+
),
|
|
918
|
+
),
|
|
919
|
+
);
|
|
920
|
+
return [
|
|
921
|
+
{
|
|
922
|
+
address: this.address,
|
|
923
|
+
stateDiff: [
|
|
924
|
+
{
|
|
925
|
+
slot: `0x${archiveSlot.toString(16).padStart(64, '0')}`,
|
|
926
|
+
value: archive.toString(),
|
|
927
|
+
},
|
|
928
|
+
],
|
|
929
|
+
},
|
|
930
|
+
];
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/** Merges multiple StateOverride arrays, combining stateDiff entries for the same address. */
|
|
934
|
+
public static mergeStateOverrides(...overrides: StateOverride[]): StateOverride {
|
|
935
|
+
type StateDiffEntry = { slot: `0x${string}`; value: `0x${string}` };
|
|
936
|
+
const byAddress = new Map<string, { address: `0x${string}`; balance?: bigint; stateDiff: StateDiffEntry[] }>();
|
|
937
|
+
for (const override of overrides) {
|
|
938
|
+
for (const entry of override) {
|
|
939
|
+
const key = entry.address.toLowerCase();
|
|
940
|
+
const existing = byAddress.get(key);
|
|
941
|
+
if (existing) {
|
|
942
|
+
existing.stateDiff.push(...(entry.stateDiff ?? []));
|
|
943
|
+
if (entry.balance !== undefined) {
|
|
944
|
+
existing.balance = entry.balance;
|
|
945
|
+
}
|
|
946
|
+
} else {
|
|
947
|
+
byAddress.set(key, {
|
|
948
|
+
address: entry.address,
|
|
949
|
+
balance: entry.balance,
|
|
950
|
+
stateDiff: [...(entry.stateDiff ?? [])],
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return [...byAddress.values()];
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/** Compresses a FeeHeader into a uint256 matching FeeHeaderLib.compress() in FeeStructs.sol. */
|
|
959
|
+
public static compressFeeHeader(feeHeader: FeeHeader): bigint {
|
|
960
|
+
const MASK_48_BITS = (1n << 48n) - 1n;
|
|
961
|
+
const MASK_64_BITS = (1n << 64n) - 1n;
|
|
962
|
+
const MASK_63_BITS = (1n << 63n) - 1n;
|
|
963
|
+
|
|
964
|
+
let value = BigInt(feeHeader.manaUsed) & ((1n << 32n) - 1n); // bits [0:31]
|
|
965
|
+
value |= (feeHeader.excessMana < MASK_48_BITS ? feeHeader.excessMana : MASK_48_BITS) << 32n; // bits [32:79]
|
|
966
|
+
value |= (BigInt(feeHeader.ethPerFeeAsset) & MASK_48_BITS) << 80n; // bits [80:127]
|
|
967
|
+
value |= (feeHeader.congestionCost < MASK_64_BITS ? feeHeader.congestionCost : MASK_64_BITS) << 128n; // bits [128:191]
|
|
968
|
+
value |= (feeHeader.proverCost < MASK_63_BITS ? feeHeader.proverCost : MASK_63_BITS) << 192n; // bits [192:254]
|
|
969
|
+
value |= 1n << 255n; // preheat flag
|
|
970
|
+
return value;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
/** Computes the fee header for a child checkpoint given parent fee header and child data.
|
|
974
|
+
* Must stay in sync with Solidity FeeLib.sol (computeNewEthPerFeeAsset, clampedAdd). */
|
|
975
|
+
public static computeChildFeeHeader(
|
|
976
|
+
parentFeeHeader: FeeHeader,
|
|
977
|
+
childManaUsed: bigint,
|
|
978
|
+
feeAssetPriceModifier: bigint,
|
|
979
|
+
manaTarget: bigint,
|
|
980
|
+
): FeeHeader {
|
|
981
|
+
const MIN_ETH_PER_FEE_ASSET = 100n;
|
|
982
|
+
const MAX_ETH_PER_FEE_ASSET = 100_000_000_000_000n; // 1e14, matches FeeLib.sol
|
|
983
|
+
|
|
984
|
+
// excessMana = clampedAdd(parent.excessMana + parent.manaUsed, -manaTarget)
|
|
985
|
+
const sum = parentFeeHeader.excessMana + parentFeeHeader.manaUsed;
|
|
986
|
+
const excessMana = sum > manaTarget ? sum - manaTarget : 0n;
|
|
987
|
+
|
|
988
|
+
// ethPerFeeAsset = computeNewEthPerFeeAsset(max(parent.ethPerFeeAsset, MIN), modifier)
|
|
989
|
+
const parentPrice =
|
|
990
|
+
parentFeeHeader.ethPerFeeAsset > MIN_ETH_PER_FEE_ASSET ? parentFeeHeader.ethPerFeeAsset : MIN_ETH_PER_FEE_ASSET;
|
|
991
|
+
let newPrice: bigint;
|
|
992
|
+
if (feeAssetPriceModifier >= 0n) {
|
|
993
|
+
newPrice = (parentPrice * (10_000n + feeAssetPriceModifier)) / 10_000n;
|
|
994
|
+
} else {
|
|
995
|
+
const absMod = -feeAssetPriceModifier;
|
|
996
|
+
newPrice = (parentPrice * (10_000n - absMod)) / 10_000n;
|
|
997
|
+
}
|
|
998
|
+
if (newPrice < MIN_ETH_PER_FEE_ASSET) {
|
|
999
|
+
newPrice = MIN_ETH_PER_FEE_ASSET;
|
|
1000
|
+
}
|
|
1001
|
+
if (newPrice > MAX_ETH_PER_FEE_ASSET) {
|
|
1002
|
+
newPrice = MAX_ETH_PER_FEE_ASSET;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
return {
|
|
1006
|
+
excessMana,
|
|
1007
|
+
manaUsed: childManaUsed,
|
|
1008
|
+
ethPerFeeAsset: newPrice,
|
|
1009
|
+
congestionCost: 0n,
|
|
1010
|
+
proverCost: 0n,
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
|
|
799
1014
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
800
1015
|
public buildInvalidateBadAttestationRequest(
|
|
801
1016
|
checkpointNumber: CheckpointNumber,
|
|
@@ -844,8 +1059,18 @@ export class RollupContract {
|
|
|
844
1059
|
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]);
|
|
845
1060
|
}
|
|
846
1061
|
|
|
847
|
-
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean): Promise<bigint> {
|
|
848
|
-
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset]);
|
|
1062
|
+
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean, stateOverride?: StateOverride): Promise<bigint> {
|
|
1063
|
+
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset], { stateOverride });
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
async getManaMinFeeComponentsAt(timestamp: bigint, inFeeAsset: boolean): Promise<ManaMinFeeComponents> {
|
|
1067
|
+
const result = await this.rollup.read.getManaMinFeeComponentsAt([timestamp, inFeeAsset]);
|
|
1068
|
+
return {
|
|
1069
|
+
sequencerCost: result.sequencerCost,
|
|
1070
|
+
proverCost: result.proverCost,
|
|
1071
|
+
congestionCost: result.congestionCost,
|
|
1072
|
+
congestionMultiplier: result.congestionMultiplier,
|
|
1073
|
+
};
|
|
849
1074
|
}
|
|
850
1075
|
|
|
851
1076
|
async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
|
|
@@ -891,11 +1116,10 @@ export class RollupContract {
|
|
|
891
1116
|
return this.rollup.read.getSpecificProverRewardsForEpoch([epoch, prover]);
|
|
892
1117
|
}
|
|
893
1118
|
|
|
894
|
-
async getAttesters(): Promise<EthAddress[]> {
|
|
1119
|
+
async getAttesters(timestamp?: bigint): Promise<EthAddress[]> {
|
|
895
1120
|
const attesterSize = await this.getActiveAttesterCount();
|
|
896
1121
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
897
|
-
const ts = (await this.client.getBlock()).timestamp;
|
|
898
|
-
|
|
1122
|
+
const ts = timestamp ?? (await this.client.getBlock()).timestamp;
|
|
899
1123
|
const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i));
|
|
900
1124
|
const chunks = chunk(indices, 1000);
|
|
901
1125
|
|
|
@@ -1001,7 +1225,7 @@ export class RollupContract {
|
|
|
1001
1225
|
}
|
|
1002
1226
|
|
|
1003
1227
|
public listenToCheckpointInvalidated(
|
|
1004
|
-
callback: (args: { checkpointNumber: CheckpointNumber }) => unknown,
|
|
1228
|
+
callback: (args: { checkpointNumber: CheckpointNumber; event: Log }) => unknown,
|
|
1005
1229
|
): WatchContractEventReturnType {
|
|
1006
1230
|
return this.rollup.watchEvent.CheckpointInvalidated(
|
|
1007
1231
|
{},
|
|
@@ -1010,7 +1234,7 @@ export class RollupContract {
|
|
|
1010
1234
|
for (const log of logs) {
|
|
1011
1235
|
const args = log.args;
|
|
1012
1236
|
if (args.checkpointNumber !== undefined) {
|
|
1013
|
-
callback({ checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber) });
|
|
1237
|
+
callback({ checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber), event: log });
|
|
1014
1238
|
}
|
|
1015
1239
|
}
|
|
1016
1240
|
},
|
|
@@ -1043,6 +1267,17 @@ export class RollupContract {
|
|
|
1043
1267
|
);
|
|
1044
1268
|
}
|
|
1045
1269
|
|
|
1270
|
+
/**
|
|
1271
|
+
* Fetches OwnershipTransferred events emitted on the L1 block this rollup was deployed on.
|
|
1272
|
+
* The Rollup inherits from Ownable and emits this event in its constructor, so the event
|
|
1273
|
+
* is guaranteed to exist on `l1StartBlock` for any correctly deployed rollup. Used as a
|
|
1274
|
+
* probe to detect RPC nodes that prune historical logs.
|
|
1275
|
+
*/
|
|
1276
|
+
async getOwnershipTransferredEventsAtDeploy() {
|
|
1277
|
+
const l1StartBlock = await this.getL1StartBlock();
|
|
1278
|
+
return await this.rollup.getEvents.OwnershipTransferred({}, { fromBlock: l1StartBlock, toBlock: l1StartBlock });
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1046
1281
|
/** Fetches CheckpointProposed events within the given block range. */
|
|
1047
1282
|
async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
|
|
1048
1283
|
const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
|
|
@@ -1056,9 +1291,58 @@ export class RollupContract {
|
|
|
1056
1291
|
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
1057
1292
|
archive: Fr.fromString(log.args.archive!),
|
|
1058
1293
|
versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
|
|
1059
|
-
attestationsHash:
|
|
1060
|
-
|
|
1294
|
+
attestationsHash: (() => {
|
|
1295
|
+
if (!log.args.attestationsHash) {
|
|
1296
|
+
throw new Error(
|
|
1297
|
+
`CheckpointProposed event missing attestationsHash for checkpoint ${log.args.checkpointNumber}`,
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
return Buffer32.fromString(log.args.attestationsHash);
|
|
1301
|
+
})(),
|
|
1302
|
+
payloadDigest: (() => {
|
|
1303
|
+
if (!log.args.payloadDigest) {
|
|
1304
|
+
throw new Error(
|
|
1305
|
+
`CheckpointProposed event missing payloadDigest for checkpoint ${log.args.checkpointNumber}`,
|
|
1306
|
+
);
|
|
1307
|
+
}
|
|
1308
|
+
return Buffer32.fromString(log.args.payloadDigest);
|
|
1309
|
+
})(),
|
|
1061
1310
|
},
|
|
1062
1311
|
}));
|
|
1063
1312
|
}
|
|
1313
|
+
|
|
1314
|
+
/** Packs pending and proven checkpoint numbers into the chain tips storage format. */
|
|
1315
|
+
static packChainTips(pendingCheckpointNumber: bigint, provenCheckpointNumber: bigint): bigint {
|
|
1316
|
+
return (pendingCheckpointNumber << 128n) | (provenCheckpointNumber & ((1n << 128n) - 1n));
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
/** Storage slot for the chain tips (offset 0 within the STF storage struct). */
|
|
1320
|
+
static get chainTipsStorageSlot(): bigint {
|
|
1321
|
+
return BigInt(RollupContract.stfStorageSlot);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/**
|
|
1325
|
+
* Computes the storage slot for a field within a tempCheckpointLog entry.
|
|
1326
|
+
* @param checkpointNumber - The checkpoint number
|
|
1327
|
+
* @param field - The field within the CompressedTempCheckpointLog struct
|
|
1328
|
+
*/
|
|
1329
|
+
async getTempCheckpointLogStorageSlot(
|
|
1330
|
+
checkpointNumber: CheckpointNumber,
|
|
1331
|
+
field: TempCheckpointLogField,
|
|
1332
|
+
): Promise<bigint> {
|
|
1333
|
+
const fieldOffset = BigInt(field);
|
|
1334
|
+
const [epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
1335
|
+
this.getEpochDuration(),
|
|
1336
|
+
this.getProofSubmissionEpochs(),
|
|
1337
|
+
]);
|
|
1338
|
+
const roundaboutSize = BigInt(epochDuration) * (BigInt(proofSubmissionEpochs) + 1n) + 1n;
|
|
1339
|
+
const tempCheckpointLogsBase = BigInt(RollupContract.stfStorageSlot) + 2n;
|
|
1340
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
1341
|
+
const entryBase = BigInt(
|
|
1342
|
+
keccak256(
|
|
1343
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsBase]),
|
|
1344
|
+
),
|
|
1345
|
+
);
|
|
1346
|
+
return entryBase + fieldOffset;
|
|
1347
|
+
}
|
|
1064
1348
|
}
|