@aztec/ethereum 0.0.1-commit.1bea0213 → 0.0.1-commit.1dcfe2301
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 +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_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 +1 -1
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +5 -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 +13 -1
- package/dest/contracts/inbox.d.ts +3 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +5 -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 +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 +88 -24
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +306 -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 +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 +9402 -15732
- 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.js +3 -3
- package/dest/test/chain_monitor.d.ts +22 -3
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +33 -2
- package/dest/test/eth_cheat_codes.d.ts +6 -4
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +6 -4
- package/dest/test/index.d.ts +1 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +0 -2
- package/dest/test/rollup_cheat_codes.d.ts +7 -1
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +18 -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 +2 -1
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +62 -12
- package/package.json +5 -7
- package/src/client.ts +10 -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_handler.ts +2 -0
- package/src/contracts/fee_asset_price_oracle.ts +280 -0
- package/src/contracts/governance.ts +5 -3
- package/src/contracts/governance_proposer.ts +10 -1
- package/src/contracts/inbox.ts +4 -4
- package/src/contracts/index.ts +3 -2
- package/src/contracts/multicall.ts +70 -3
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +335 -59
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +16 -14
- 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 +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 +3 -3
- 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 +20 -1
- 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,6 +4,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
4
4
|
import { memoize } from '@aztec/foundation/decorators';
|
|
5
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
6
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
7
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
7
8
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
8
9
|
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
9
10
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
type Hex,
|
|
17
18
|
type StateOverride,
|
|
18
19
|
type WatchContractEventReturnType,
|
|
20
|
+
encodeAbiParameters,
|
|
19
21
|
encodeFunctionData,
|
|
20
22
|
getContract,
|
|
21
23
|
hexToBigInt,
|
|
@@ -29,11 +31,10 @@ import type { L1ReaderConfig } from '../l1_reader.js';
|
|
|
29
31
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
30
32
|
import type { ViemClient } from '../types.js';
|
|
31
33
|
import { formatViemError } from '../utils.js';
|
|
32
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
33
34
|
import { GSEContract } from './gse.js';
|
|
34
35
|
import type { L1EventLog } from './log.js';
|
|
35
36
|
import { SlasherContract } from './slasher_contract.js';
|
|
36
|
-
import {
|
|
37
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
37
38
|
import { checkBlockTag } from './utils.js';
|
|
38
39
|
|
|
39
40
|
export type ViemCommitteeAttestation = {
|
|
@@ -55,7 +56,6 @@ export type L1RollupContractAddresses = Pick<
|
|
|
55
56
|
| 'feeJuiceAddress'
|
|
56
57
|
| 'stakingAssetAddress'
|
|
57
58
|
| 'rewardDistributorAddress'
|
|
58
|
-
| 'slashFactoryAddress'
|
|
59
59
|
| 'gseAddress'
|
|
60
60
|
>;
|
|
61
61
|
|
|
@@ -85,12 +85,6 @@ export type ViemGasFees = {
|
|
|
85
85
|
feePerL2Gas: bigint;
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
-
export enum SlashingProposerType {
|
|
89
|
-
None = 0,
|
|
90
|
-
Tally = 1,
|
|
91
|
-
Empire = 2,
|
|
92
|
-
}
|
|
93
|
-
|
|
94
88
|
/**
|
|
95
89
|
* Status of a validator/attester in the staking system.
|
|
96
90
|
* Matches the Status enum in StakingLib.sol
|
|
@@ -134,6 +128,25 @@ export type L1FeeData = {
|
|
|
134
128
|
blobFee: bigint;
|
|
135
129
|
};
|
|
136
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
|
+
|
|
137
150
|
/**
|
|
138
151
|
* Reward configuration for the rollup
|
|
139
152
|
*/
|
|
@@ -193,10 +206,10 @@ export type CheckpointProposedArgs = {
|
|
|
193
206
|
checkpointNumber: CheckpointNumber;
|
|
194
207
|
archive: Fr;
|
|
195
208
|
versionedBlobHashes: Buffer[];
|
|
196
|
-
/** Hash of attestations
|
|
197
|
-
attestationsHash
|
|
198
|
-
/** Digest of the payload
|
|
199
|
-
payloadDigest
|
|
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;
|
|
200
213
|
};
|
|
201
214
|
|
|
202
215
|
/** Log type for CheckpointProposed events. */
|
|
@@ -204,6 +217,7 @@ export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
|
204
217
|
|
|
205
218
|
export class RollupContract {
|
|
206
219
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
220
|
+
private readonly logger = createLogger('ethereum:rollup');
|
|
207
221
|
|
|
208
222
|
private static cachedStfStorageSlot: Hex | undefined;
|
|
209
223
|
private cachedEscapeHatch?: {
|
|
@@ -259,34 +273,18 @@ export class RollupContract {
|
|
|
259
273
|
return this.rollup;
|
|
260
274
|
}
|
|
261
275
|
|
|
262
|
-
public async getSlashingProposer(): Promise<
|
|
263
|
-
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
264
|
-
> {
|
|
276
|
+
public async getSlashingProposer(): Promise<SlashingProposerContract | undefined> {
|
|
265
277
|
const slasher = await this.getSlasherContract();
|
|
266
278
|
if (!slasher) {
|
|
267
279
|
return undefined;
|
|
268
280
|
}
|
|
269
281
|
|
|
270
282
|
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}`);
|
|
283
|
+
if (proposerAddress.isZero()) {
|
|
284
|
+
return undefined;
|
|
289
285
|
}
|
|
286
|
+
|
|
287
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
290
288
|
}
|
|
291
289
|
|
|
292
290
|
@memoize
|
|
@@ -379,6 +377,20 @@ export class RollupContract {
|
|
|
379
377
|
return Fr.fromString(await this.rollup.read.archiveAt([0n]));
|
|
380
378
|
}
|
|
381
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
|
+
|
|
382
394
|
/**
|
|
383
395
|
* Returns rollup constants used for epoch queries.
|
|
384
396
|
* Return type is `L1RollupConstants` which is defined in stdlib,
|
|
@@ -391,13 +403,25 @@ export class RollupContract {
|
|
|
391
403
|
slotDuration: number;
|
|
392
404
|
epochDuration: number;
|
|
393
405
|
proofSubmissionEpochs: number;
|
|
406
|
+
targetCommitteeSize: number;
|
|
407
|
+
rollupManaLimit: number;
|
|
394
408
|
}> {
|
|
395
|
-
const [
|
|
409
|
+
const [
|
|
410
|
+
l1StartBlock,
|
|
411
|
+
l1GenesisTime,
|
|
412
|
+
slotDuration,
|
|
413
|
+
epochDuration,
|
|
414
|
+
proofSubmissionEpochs,
|
|
415
|
+
targetCommitteeSize,
|
|
416
|
+
rollupManaLimit,
|
|
417
|
+
] = await Promise.all([
|
|
396
418
|
this.getL1StartBlock(),
|
|
397
419
|
this.getL1GenesisTime(),
|
|
398
420
|
this.getSlotDuration(),
|
|
399
421
|
this.getEpochDuration(),
|
|
400
422
|
this.getProofSubmissionEpochs(),
|
|
423
|
+
this.getTargetCommitteeSize(),
|
|
424
|
+
this.getManaLimit(),
|
|
401
425
|
]);
|
|
402
426
|
return {
|
|
403
427
|
l1StartBlock,
|
|
@@ -405,6 +429,8 @@ export class RollupContract {
|
|
|
405
429
|
slotDuration,
|
|
406
430
|
epochDuration: Number(epochDuration),
|
|
407
431
|
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
432
|
+
targetCommitteeSize,
|
|
433
|
+
rollupManaLimit: Number(rollupManaLimit),
|
|
408
434
|
};
|
|
409
435
|
}
|
|
410
436
|
|
|
@@ -459,7 +485,11 @@ export class RollupContract {
|
|
|
459
485
|
|
|
460
486
|
const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
|
|
461
487
|
return isOpen;
|
|
462
|
-
} catch {
|
|
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
|
+
});
|
|
463
493
|
return false;
|
|
464
494
|
}
|
|
465
495
|
}
|
|
@@ -495,26 +525,41 @@ export class RollupContract {
|
|
|
495
525
|
return this.rollup.read.getCheckpointReward();
|
|
496
526
|
}
|
|
497
527
|
|
|
498
|
-
async getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
499
|
-
|
|
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));
|
|
500
531
|
}
|
|
501
532
|
|
|
502
|
-
async getProvenCheckpointNumber(): Promise<CheckpointNumber> {
|
|
503
|
-
|
|
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));
|
|
504
536
|
}
|
|
505
537
|
|
|
506
|
-
async getSlotNumber(): Promise<SlotNumber> {
|
|
507
|
-
|
|
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));
|
|
508
541
|
}
|
|
509
542
|
|
|
510
|
-
async getL1FeesAt(timestamp: bigint): Promise<L1FeeData> {
|
|
511
|
-
|
|
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);
|
|
512
546
|
return {
|
|
513
547
|
baseFee: result.baseFee,
|
|
514
548
|
blobFee: result.blobFee,
|
|
515
549
|
};
|
|
516
550
|
}
|
|
517
551
|
|
|
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
|
+
|
|
518
563
|
getEthPerFeeAsset(): Promise<bigint> {
|
|
519
564
|
return this.rollup.read.getEthPerFeeAsset();
|
|
520
565
|
}
|
|
@@ -589,8 +634,9 @@ export class RollupContract {
|
|
|
589
634
|
return EthAddress.fromString(result);
|
|
590
635
|
}
|
|
591
636
|
|
|
592
|
-
async getCheckpoint(checkpointNumber: CheckpointNumber): Promise<CheckpointLog> {
|
|
593
|
-
|
|
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);
|
|
594
640
|
return {
|
|
595
641
|
archive: Fr.fromString(result.archive),
|
|
596
642
|
headerHash: Buffer32.fromString(result.headerHash),
|
|
@@ -623,6 +669,30 @@ export class RollupContract {
|
|
|
623
669
|
);
|
|
624
670
|
}
|
|
625
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
|
+
|
|
626
696
|
async getTips(): Promise<{ pending: CheckpointNumber; proven: CheckpointNumber }> {
|
|
627
697
|
const { pending, proven } = await this.rollup.read.getTips();
|
|
628
698
|
return {
|
|
@@ -741,14 +811,13 @@ export class RollupContract {
|
|
|
741
811
|
* timestamp of the next L1 block
|
|
742
812
|
* @throws otherwise
|
|
743
813
|
*/
|
|
744
|
-
public async
|
|
814
|
+
public async canProposeAt(
|
|
745
815
|
archive: Buffer,
|
|
746
816
|
account: `0x${string}` | Account,
|
|
747
|
-
|
|
748
|
-
|
|
817
|
+
timestamp: bigint,
|
|
818
|
+
stateOverride: StateOverride = [],
|
|
749
819
|
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
750
|
-
const
|
|
751
|
-
const timeOfNextL1Slot = latestBlock.timestamp + BigInt(slotDuration);
|
|
820
|
+
const timeOfNextL1Slot = timestamp;
|
|
752
821
|
const who = typeof account === 'string' ? account : account.address;
|
|
753
822
|
|
|
754
823
|
try {
|
|
@@ -760,7 +829,7 @@ export class RollupContract {
|
|
|
760
829
|
functionName: 'canProposeAtTime',
|
|
761
830
|
args: [timeOfNextL1Slot, `0x${archive.toString('hex')}`, who],
|
|
762
831
|
account,
|
|
763
|
-
stateOverride
|
|
832
|
+
stateOverride,
|
|
764
833
|
});
|
|
765
834
|
|
|
766
835
|
return {
|
|
@@ -796,6 +865,151 @@ export class RollupContract {
|
|
|
796
865
|
];
|
|
797
866
|
}
|
|
798
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
|
+
|
|
799
1013
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
800
1014
|
public buildInvalidateBadAttestationRequest(
|
|
801
1015
|
checkpointNumber: CheckpointNumber,
|
|
@@ -805,6 +1019,7 @@ export class RollupContract {
|
|
|
805
1019
|
): L1TxRequest {
|
|
806
1020
|
return {
|
|
807
1021
|
to: this.address,
|
|
1022
|
+
abi: RollupAbi,
|
|
808
1023
|
data: encodeFunctionData({
|
|
809
1024
|
abi: RollupAbi,
|
|
810
1025
|
functionName: 'invalidateBadAttestation',
|
|
@@ -826,6 +1041,7 @@ export class RollupContract {
|
|
|
826
1041
|
): L1TxRequest {
|
|
827
1042
|
return {
|
|
828
1043
|
to: this.address,
|
|
1044
|
+
abi: RollupAbi,
|
|
829
1045
|
data: encodeFunctionData({
|
|
830
1046
|
abi: RollupAbi,
|
|
831
1047
|
functionName: 'invalidateInsufficientAttestations',
|
|
@@ -842,8 +1058,18 @@ export class RollupContract {
|
|
|
842
1058
|
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]);
|
|
843
1059
|
}
|
|
844
1060
|
|
|
845
|
-
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean): Promise<bigint> {
|
|
846
|
-
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
|
+
};
|
|
847
1073
|
}
|
|
848
1074
|
|
|
849
1075
|
async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
|
|
@@ -889,11 +1115,10 @@ export class RollupContract {
|
|
|
889
1115
|
return this.rollup.read.getSpecificProverRewardsForEpoch([epoch, prover]);
|
|
890
1116
|
}
|
|
891
1117
|
|
|
892
|
-
async getAttesters(): Promise<EthAddress[]> {
|
|
1118
|
+
async getAttesters(timestamp?: bigint): Promise<EthAddress[]> {
|
|
893
1119
|
const attesterSize = await this.getActiveAttesterCount();
|
|
894
1120
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
895
|
-
const ts = (await this.client.getBlock()).timestamp;
|
|
896
|
-
|
|
1121
|
+
const ts = timestamp ?? (await this.client.getBlock()).timestamp;
|
|
897
1122
|
const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i));
|
|
898
1123
|
const chunks = chunk(indices, 1000);
|
|
899
1124
|
|
|
@@ -959,6 +1184,7 @@ export class RollupContract {
|
|
|
959
1184
|
setupEpoch(l1TxUtils: L1TxUtils) {
|
|
960
1185
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
961
1186
|
to: this.address,
|
|
1187
|
+
abi: RollupAbi,
|
|
962
1188
|
data: encodeFunctionData({
|
|
963
1189
|
abi: RollupAbi,
|
|
964
1190
|
functionName: 'setupEpoch',
|
|
@@ -970,6 +1196,7 @@ export class RollupContract {
|
|
|
970
1196
|
vote(l1TxUtils: L1TxUtils, proposalId: bigint) {
|
|
971
1197
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
972
1198
|
to: this.address,
|
|
1199
|
+
abi: RollupAbi,
|
|
973
1200
|
data: encodeFunctionData({
|
|
974
1201
|
abi: RollupAbi,
|
|
975
1202
|
functionName: 'vote',
|
|
@@ -1052,9 +1279,58 @@ export class RollupContract {
|
|
|
1052
1279
|
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
1053
1280
|
archive: Fr.fromString(log.args.archive!),
|
|
1054
1281
|
versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
|
|
1055
|
-
attestationsHash:
|
|
1056
|
-
|
|
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
|
+
})(),
|
|
1057
1298
|
},
|
|
1058
1299
|
}));
|
|
1059
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
|
+
}
|
|
1060
1336
|
}
|