@aztec/ethereum 0.0.1-commit.b655e406 → 0.0.1-commit.b8a057fa
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/account.d.ts +1 -1
- package/dest/chain.d.ts +1 -1
- package/dest/client.d.ts +25 -3
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +60 -4
- package/dest/config.d.ts +48 -73
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +120 -386
- package/dest/constants.d.ts +1 -1
- package/dest/contracts/chain_state_override.d.ts +78 -0
- package/dest/contracts/chain_state_override.d.ts.map +1 -0
- package/dest/contracts/chain_state_override.js +137 -0
- package/dest/contracts/empire_base.d.ts +7 -5
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/empire_base.js +1 -1
- package/dest/contracts/errors.d.ts +1 -1
- package/dest/contracts/errors.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.d.ts +6 -5
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.js +11 -9
- package/dest/contracts/fee_asset_price_oracle.d.ts +105 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
- package/dest/contracts/fee_asset_price_oracle.js +656 -0
- package/dest/contracts/fee_juice.d.ts +1 -1
- package/dest/contracts/fee_juice.d.ts.map +1 -1
- package/dest/contracts/governance.d.ts +113 -36
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +207 -16
- package/dest/contracts/governance_proposer.d.ts +38 -4
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +455 -12
- package/dest/contracts/gse.d.ts +4 -2
- package/dest/contracts/gse.d.ts.map +1 -1
- package/dest/contracts/gse.js +2 -2
- package/dest/contracts/inbox.d.ts +24 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +42 -2
- package/dest/contracts/index.d.ts +6 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +5 -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 +130 -13
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +203 -93
- package/dest/contracts/outbox.d.ts +64 -0
- package/dest/contracts/outbox.d.ts.map +1 -0
- package/dest/contracts/outbox.js +113 -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 +5591 -131
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +1125 -232
- package/dest/contracts/slasher_contract.d.ts +1 -1
- package/dest/contracts/slasher_contract.d.ts.map +1 -1
- package/dest/contracts/{tally_slashing_proposer.d.ts → slashing_proposer.d.ts} +11 -10
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/{tally_slashing_proposer.js → slashing_proposer.js} +21 -16
- package/dest/contracts/utils.d.ts +1 -1
- package/dest/deploy_aztec_l1_contracts.d.ts +267 -0
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
- package/dest/deploy_aztec_l1_contracts.js +417 -0
- package/dest/deploy_l1_contract.d.ts +68 -0
- package/dest/deploy_l1_contract.d.ts.map +1 -0
- package/dest/deploy_l1_contract.js +312 -0
- package/dest/eth-signer/eth-signer.d.ts +1 -1
- package/dest/eth-signer/index.d.ts +1 -1
- package/dest/forwarder_proxy.d.ts +32 -0
- package/dest/forwarder_proxy.d.ts.map +1 -0
- package/dest/forwarder_proxy.js +93 -0
- package/dest/l1_artifacts.d.ts +21007 -16779
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +9 -24
- package/dest/l1_contract_addresses.d.ts +61 -65
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +99 -80
- package/dest/l1_reader.d.ts +7 -5
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +15 -7
- package/dest/l1_tx_utils/config.d.ts +11 -5
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +46 -10
- package/dest/l1_tx_utils/constants.d.ts +8 -2
- package/dest/l1_tx_utils/constants.d.ts.map +1 -1
- package/dest/l1_tx_utils/constants.js +27 -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/index.d.ts +10 -0
- package/dest/l1_tx_utils/fee-strategies/index.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/index.js +12 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts +8 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +129 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts +23 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +191 -0
- package/dest/l1_tx_utils/fee-strategies/types.d.ts +51 -0
- package/dest/l1_tx_utils/fee-strategies/types.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/types.js +3 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +41 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +42 -0
- package/dest/l1_tx_utils/index-blobs.d.ts +3 -0
- package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -0
- package/dest/l1_tx_utils/index-blobs.js +2 -0
- package/dest/l1_tx_utils/index.d.ts +4 -1
- package/dest/l1_tx_utils/index.d.ts.map +1 -1
- package/dest/l1_tx_utils/index.js +3 -0
- package/dest/l1_tx_utils/interfaces.d.ts +2 -2
- package/dest/l1_tx_utils/interfaces.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +252 -0
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -0
- package/dest/l1_tx_utils/l1_fee_analyzer.js +568 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +26 -8
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +202 -92
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +19 -30
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +65 -168
- package/dest/l1_tx_utils/signer.d.ts +1 -1
- package/dest/l1_tx_utils/tx_delayer.d.ts +58 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
- package/dest/{test → l1_tx_utils}/tx_delayer.js +70 -39
- package/dest/l1_tx_utils/types.d.ts +27 -1
- package/dest/l1_tx_utils/types.d.ts.map +1 -1
- package/dest/l1_tx_utils/types.js +10 -0
- package/dest/l1_tx_utils/utils.d.ts +1 -1
- package/dest/l1_types.d.ts +1 -1
- package/dest/publisher_manager.d.ts +34 -7
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +119 -8
- package/dest/queries.d.ts +14 -3
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +84 -9
- package/dest/test/blob_kzg_warmup.d.ts +19 -0
- package/dest/test/blob_kzg_warmup.d.ts.map +1 -0
- package/dest/test/blob_kzg_warmup.js +64 -0
- package/dest/test/chain_monitor.d.ts +80 -26
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +137 -39
- package/dest/test/eth_cheat_codes.d.ts +47 -8
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +100 -44
- package/dest/test/eth_cheat_codes_with_state.d.ts +1 -1
- package/dest/test/eth_cheat_codes_with_state.d.ts.map +1 -1
- package/dest/test/index.d.ts +2 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +1 -2
- package/dest/test/rollup_cheat_codes.d.ts +75 -14
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +145 -42
- package/dest/test/start_anvil.d.ts +25 -2
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +143 -28
- package/dest/test/upgrade_utils.d.ts +1 -1
- package/dest/test/upgrade_utils.js +2 -2
- package/dest/types.d.ts +57 -2
- package/dest/types.d.ts.map +1 -1
- package/dest/utils.d.ts +24 -4
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +112 -16
- package/dest/zkPassportVerifierAddress.d.ts +1 -1
- package/package.json +34 -17
- package/src/client.ts +66 -2
- package/src/config.ts +162 -470
- package/src/contracts/README.md +157 -0
- package/src/contracts/chain_state_override.ts +200 -0
- package/src/contracts/empire_base.ts +6 -5
- package/src/contracts/fee_asset_handler.ts +10 -7
- package/src/contracts/fee_asset_price_oracle.ts +285 -0
- package/src/contracts/governance.ts +279 -13
- package/src/contracts/governance_proposer.ts +74 -7
- package/src/contracts/gse.ts +7 -2
- package/src/contracts/inbox.ts +64 -4
- package/src/contracts/index.ts +5 -2
- package/src/contracts/log.ts +13 -0
- package/src/contracts/multicall.ts +247 -103
- package/src/contracts/outbox.ts +132 -0
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +830 -194
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +26 -21
- package/src/deploy_aztec_l1_contracts.ts +652 -0
- package/src/deploy_l1_contract.ts +362 -0
- package/src/forwarder_proxy.ts +108 -0
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +120 -92
- package/src/l1_reader.ts +25 -10
- package/src/l1_tx_utils/config.ts +55 -14
- package/src/l1_tx_utils/constants.ts +13 -2
- package/src/l1_tx_utils/factory.ts +31 -31
- package/src/l1_tx_utils/fee-strategies/index.ts +22 -0
- package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +163 -0
- package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +245 -0
- package/src/l1_tx_utils/fee-strategies/types.ts +56 -0
- package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +108 -0
- package/src/l1_tx_utils/index-blobs.ts +2 -0
- package/src/l1_tx_utils/index.ts +3 -0
- package/src/l1_tx_utils/interfaces.ts +1 -1
- package/src/l1_tx_utils/l1_fee_analyzer.ts +875 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +194 -72
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +79 -214
- package/src/{test → l1_tx_utils}/tx_delayer.ts +97 -58
- package/src/l1_tx_utils/types.ts +32 -0
- package/src/publisher_manager.ts +145 -12
- package/src/queries.ts +93 -10
- package/src/test/blob_kzg_warmup.ts +65 -0
- package/src/test/chain_monitor.ts +198 -51
- package/src/test/eth_cheat_codes.ts +91 -48
- package/src/test/index.ts +1 -2
- package/src/test/rollup_cheat_codes.ts +174 -45
- package/src/test/start_anvil.ts +179 -27
- package/src/test/upgrade_utils.ts +2 -2
- package/src/types.ts +62 -0
- package/src/utils.ts +128 -19
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -65
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -194
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- package/dest/deploy_l1_contracts.d.ts +0 -226
- package/dest/deploy_l1_contracts.d.ts.map +0 -1
- package/dest/deploy_l1_contracts.js +0 -1473
- package/dest/index.d.ts +0 -18
- package/dest/index.d.ts.map +0 -1
- package/dest/index.js +0 -17
- 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/deploy_l1_contracts.ts +0 -1849
- package/src/index.ts +0 -17
- 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
|
@@ -1,16 +1,28 @@
|
|
|
1
|
+
import { CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
1
4
|
import { memoize } from '@aztec/foundation/decorators';
|
|
2
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
6
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
7
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
8
|
+
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
9
|
+
import { getErrorCause } from '@aztec/foundation/types';
|
|
10
|
+
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
4
11
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
5
12
|
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
6
13
|
|
|
7
14
|
import chunk from 'lodash.chunk';
|
|
8
15
|
import {
|
|
9
16
|
type Account,
|
|
17
|
+
ContractFunctionRevertedError,
|
|
10
18
|
type GetContractReturnType,
|
|
11
19
|
type Hex,
|
|
20
|
+
type Log,
|
|
21
|
+
RpcRequestError,
|
|
12
22
|
type StateOverride,
|
|
13
23
|
type WatchContractEventReturnType,
|
|
24
|
+
decodeErrorResult,
|
|
25
|
+
encodeAbiParameters,
|
|
14
26
|
encodeFunctionData,
|
|
15
27
|
getContract,
|
|
16
28
|
hexToBigInt,
|
|
@@ -18,16 +30,16 @@ import {
|
|
|
18
30
|
} from 'viem';
|
|
19
31
|
|
|
20
32
|
import { getPublicClient } from '../client.js';
|
|
21
|
-
import type {
|
|
33
|
+
import type { DeployAztecL1ContractsReturnType } from '../deploy_aztec_l1_contracts.js';
|
|
22
34
|
import type { L1ContractAddresses } from '../l1_contract_addresses.js';
|
|
23
35
|
import type { L1ReaderConfig } from '../l1_reader.js';
|
|
24
36
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
25
37
|
import type { ViemClient } from '../types.js';
|
|
26
38
|
import { formatViemError } from '../utils.js';
|
|
27
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
28
39
|
import { GSEContract } from './gse.js';
|
|
40
|
+
import type { L1EventLog } from './log.js';
|
|
29
41
|
import { SlasherContract } from './slasher_contract.js';
|
|
30
|
-
import {
|
|
42
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
31
43
|
import { checkBlockTag } from './utils.js';
|
|
32
44
|
|
|
33
45
|
export type ViemCommitteeAttestation = {
|
|
@@ -49,31 +61,29 @@ export type L1RollupContractAddresses = Pick<
|
|
|
49
61
|
| 'feeJuiceAddress'
|
|
50
62
|
| 'stakingAssetAddress'
|
|
51
63
|
| 'rewardDistributorAddress'
|
|
52
|
-
| 'slashFactoryAddress'
|
|
53
64
|
| 'gseAddress'
|
|
54
65
|
>;
|
|
55
66
|
|
|
56
67
|
export type EpochProofPublicInputArgs = {
|
|
57
68
|
previousArchive: `0x${string}`;
|
|
58
69
|
endArchive: `0x${string}`;
|
|
70
|
+
outHash: `0x${string}`;
|
|
59
71
|
proverId: `0x${string}`;
|
|
60
72
|
};
|
|
61
73
|
|
|
62
74
|
export type ViemHeader = {
|
|
63
75
|
lastArchiveRoot: `0x${string}`;
|
|
64
|
-
|
|
76
|
+
blockHeadersHash: `0x${string}`;
|
|
77
|
+
blobsHash: `0x${string}`;
|
|
78
|
+
inHash: `0x${string}`;
|
|
79
|
+
outHash: `0x${string}`;
|
|
65
80
|
slotNumber: bigint;
|
|
66
81
|
timestamp: bigint;
|
|
67
82
|
coinbase: `0x${string}`;
|
|
68
83
|
feeRecipient: `0x${string}`;
|
|
69
84
|
gasFees: ViemGasFees;
|
|
70
85
|
totalManaUsed: bigint;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
export type ViemContentCommitment = {
|
|
74
|
-
blobsHash: `0x${string}`;
|
|
75
|
-
inHash: `0x${string}`;
|
|
76
|
-
outHash: `0x${string}`;
|
|
86
|
+
accumulatedFees: bigint;
|
|
77
87
|
};
|
|
78
88
|
|
|
79
89
|
export type ViemGasFees = {
|
|
@@ -81,32 +91,185 @@ export type ViemGasFees = {
|
|
|
81
91
|
feePerL2Gas: bigint;
|
|
82
92
|
};
|
|
83
93
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Status of a validator/attester in the staking system.
|
|
96
|
+
* Matches the Status enum in StakingLib.sol
|
|
97
|
+
*/
|
|
98
|
+
export enum AttesterStatus {
|
|
99
|
+
NONE = 0,
|
|
100
|
+
VALIDATING = 1,
|
|
101
|
+
ZOMBIE = 2,
|
|
102
|
+
EXITING = 3,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Fee header data for a checkpoint
|
|
107
|
+
*/
|
|
108
|
+
export type FeeHeader = {
|
|
109
|
+
excessMana: bigint;
|
|
110
|
+
manaUsed: bigint;
|
|
111
|
+
ethPerFeeAsset: bigint;
|
|
112
|
+
congestionCost: bigint;
|
|
113
|
+
proverCost: bigint;
|
|
87
114
|
};
|
|
88
115
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Checkpoint log data returned from the rollup contract
|
|
118
|
+
*/
|
|
119
|
+
export type CheckpointLog = {
|
|
120
|
+
archive: Fr;
|
|
121
|
+
headerHash: Buffer32;
|
|
122
|
+
blobCommitmentsHash: Buffer32;
|
|
123
|
+
attestationsHash: Buffer32;
|
|
124
|
+
payloadDigest: Buffer32;
|
|
125
|
+
slotNumber: SlotNumber;
|
|
126
|
+
feeHeader: FeeHeader;
|
|
93
127
|
};
|
|
94
128
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
129
|
+
/**
|
|
130
|
+
* L1 fee data (base fee and blob fee)
|
|
131
|
+
*/
|
|
132
|
+
export type L1FeeData = {
|
|
133
|
+
baseFee: bigint;
|
|
134
|
+
blobFee: bigint;
|
|
98
135
|
};
|
|
99
136
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
137
|
+
/** Field offsets within the CompressedTempCheckpointLog struct in Solidity storage. */
|
|
138
|
+
export enum TempCheckpointLogField {
|
|
139
|
+
HeaderHash = 0,
|
|
140
|
+
BlobCommitmentsHash = 1,
|
|
141
|
+
OutHash = 2,
|
|
142
|
+
AttestationsHash = 3,
|
|
143
|
+
PayloadDigest = 4,
|
|
144
|
+
SlotNumber = 5,
|
|
145
|
+
FeeHeader = 6,
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Field-level override input for `tempCheckpointLogs[checkpointNumber]`. Covers the fields the
|
|
150
|
+
* `propose()` path actually reads back. `payloadDigest` is `Buffer32` because it carries an
|
|
151
|
+
* arbitrary `bytes32` value rather than a BN254 scalar. `slotNumber` carries the uint32 portion
|
|
152
|
+
* of the on-chain `CompressedSlot`.
|
|
153
|
+
*/
|
|
154
|
+
export type TempCheckpointLogOverrideFields = {
|
|
155
|
+
headerHash?: Fr;
|
|
156
|
+
outHash?: Fr;
|
|
157
|
+
payloadDigest?: Buffer32;
|
|
158
|
+
slotNumber?: SlotNumber;
|
|
159
|
+
feeHeader?: FeeHeader;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
/** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
|
|
163
|
+
export type ManaMinFeeComponents = {
|
|
164
|
+
sequencerCost: bigint;
|
|
165
|
+
proverCost: bigint;
|
|
166
|
+
congestionCost: bigint;
|
|
167
|
+
congestionMultiplier: bigint;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Reward configuration for the rollup
|
|
172
|
+
*/
|
|
173
|
+
export type RewardConfig = {
|
|
174
|
+
rewardDistributor: EthAddress;
|
|
175
|
+
sequencerBps: bigint;
|
|
176
|
+
booster: EthAddress;
|
|
177
|
+
checkpointReward: bigint;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Exit information for a validator
|
|
182
|
+
*/
|
|
183
|
+
export type Exit = {
|
|
184
|
+
withdrawalId: bigint;
|
|
185
|
+
amount: bigint;
|
|
186
|
+
exitableAt: bigint;
|
|
187
|
+
recipientOrWithdrawer: EthAddress;
|
|
188
|
+
isRecipient: boolean;
|
|
189
|
+
exists: boolean;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Attester configuration including public key and withdrawer
|
|
194
|
+
*/
|
|
195
|
+
export type AttesterConfig = {
|
|
196
|
+
publicKey: {
|
|
197
|
+
x: bigint;
|
|
198
|
+
y: bigint;
|
|
199
|
+
};
|
|
200
|
+
withdrawer: EthAddress;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Complete view of an attester's state
|
|
205
|
+
*/
|
|
206
|
+
export type AttesterView = {
|
|
207
|
+
status: AttesterStatus;
|
|
208
|
+
effectiveBalance: bigint;
|
|
209
|
+
exit: Exit;
|
|
210
|
+
config: AttesterConfig;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Return for a status call
|
|
215
|
+
*/
|
|
216
|
+
export type RollupStatusResponse = {
|
|
217
|
+
provenCheckpointNumber: CheckpointNumber;
|
|
218
|
+
provenArchive: Fr;
|
|
219
|
+
pendingCheckpointNumber: CheckpointNumber;
|
|
220
|
+
pendingArchive: Fr;
|
|
221
|
+
archiveOfMyCheckpoint: Fr;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/** Arguments for the CheckpointProposed event. */
|
|
225
|
+
export type CheckpointProposedArgs = {
|
|
226
|
+
checkpointNumber: CheckpointNumber;
|
|
227
|
+
archive: Fr;
|
|
228
|
+
versionedBlobHashes: Buffer[];
|
|
229
|
+
/** Hash of attestations emitted in the CheckpointProposed event. */
|
|
230
|
+
attestationsHash: Buffer32;
|
|
231
|
+
/** Digest of the payload emitted in the CheckpointProposed event. */
|
|
232
|
+
payloadDigest: Buffer32;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
/** Log type for CheckpointProposed events. */
|
|
236
|
+
export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
237
|
+
|
|
238
|
+
const INSUFFICIENT_VALIDATOR_SET_SIZE_ERROR = 'ValidatorSelection__InsufficientValidatorSetSize';
|
|
239
|
+
|
|
240
|
+
function isValidatorSelectionError(err: unknown, errorName: string): boolean {
|
|
241
|
+
return (
|
|
242
|
+
getErrorCause(err, ContractFunctionRevertedError)?.data?.errorName === errorName ||
|
|
243
|
+
decodeRpcRequestErrorName(err) === errorName
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function decodeRpcRequestErrorName(err: unknown): string | undefined {
|
|
248
|
+
const data = getErrorCause(err, RpcRequestError)?.data;
|
|
249
|
+
if (!isHexString(data)) {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
return decodeErrorResult({ abi: RollupAbi, data }).errorName;
|
|
255
|
+
} catch {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function isHexString(value: unknown): value is Hex {
|
|
261
|
+
return typeof value === 'string' && value.startsWith('0x');
|
|
104
262
|
}
|
|
105
263
|
|
|
106
264
|
export class RollupContract {
|
|
107
265
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
266
|
+
private readonly logger = createLogger('ethereum:rollup');
|
|
108
267
|
|
|
109
268
|
private static cachedStfStorageSlot: Hex | undefined;
|
|
269
|
+
private cachedEscapeHatch?: {
|
|
270
|
+
address: EthAddress;
|
|
271
|
+
contract: GetContractReturnType<typeof EscapeHatchAbi, ViemClient>;
|
|
272
|
+
};
|
|
110
273
|
|
|
111
274
|
static get checkBlobStorageSlot(): bigint {
|
|
112
275
|
const asString = RollupStorage.find(storage => storage.label === 'checkBlob')?.slot;
|
|
@@ -120,7 +283,7 @@ export class RollupContract {
|
|
|
120
283
|
return (RollupContract.cachedStfStorageSlot ??= keccak256(Buffer.from('aztec.stf.storage', 'utf-8')));
|
|
121
284
|
}
|
|
122
285
|
|
|
123
|
-
static getFromL1ContractsValues(deployL1ContractsValues:
|
|
286
|
+
static getFromL1ContractsValues(deployL1ContractsValues: DeployAztecL1ContractsReturnType) {
|
|
124
287
|
const {
|
|
125
288
|
l1Client,
|
|
126
289
|
l1ContractAddresses: { rollupAddress },
|
|
@@ -130,7 +293,7 @@ export class RollupContract {
|
|
|
130
293
|
|
|
131
294
|
static getFromConfig(config: L1ReaderConfig) {
|
|
132
295
|
const client = getPublicClient(config);
|
|
133
|
-
const address = config.
|
|
296
|
+
const address = config.rollupAddress.toString();
|
|
134
297
|
return new RollupContract(client, address);
|
|
135
298
|
}
|
|
136
299
|
|
|
@@ -144,8 +307,8 @@ export class RollupContract {
|
|
|
144
307
|
this.rollup = getContract({ address, abi: RollupAbi, client });
|
|
145
308
|
}
|
|
146
309
|
|
|
147
|
-
getGSE() {
|
|
148
|
-
return this.rollup.read.getGSE();
|
|
310
|
+
async getGSE(): Promise<EthAddress> {
|
|
311
|
+
return EthAddress.fromString(await this.rollup.read.getGSE());
|
|
149
312
|
}
|
|
150
313
|
|
|
151
314
|
public get address() {
|
|
@@ -156,119 +319,122 @@ export class RollupContract {
|
|
|
156
319
|
return this.rollup;
|
|
157
320
|
}
|
|
158
321
|
|
|
159
|
-
public async getSlashingProposer(): Promise<
|
|
160
|
-
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
161
|
-
> {
|
|
322
|
+
public async getSlashingProposer(): Promise<SlashingProposerContract | undefined> {
|
|
162
323
|
const slasher = await this.getSlasherContract();
|
|
163
324
|
if (!slasher) {
|
|
164
325
|
return undefined;
|
|
165
326
|
}
|
|
166
327
|
|
|
167
328
|
const proposerAddress = await slasher.getProposer();
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
type: 'function',
|
|
171
|
-
name: 'SLASHING_PROPOSER_TYPE',
|
|
172
|
-
inputs: [],
|
|
173
|
-
outputs: [{ name: '', type: 'uint8', internalType: 'enum SlasherFlavor' }],
|
|
174
|
-
stateMutability: 'view',
|
|
175
|
-
},
|
|
176
|
-
] as const;
|
|
177
|
-
|
|
178
|
-
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
|
|
179
|
-
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
180
|
-
if (proposerType === SlashingProposerType.Tally.valueOf()) {
|
|
181
|
-
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
182
|
-
} else if (proposerType === SlashingProposerType.Empire.valueOf()) {
|
|
183
|
-
return new EmpireSlashingProposerContract(this.client, proposerAddress);
|
|
184
|
-
} else {
|
|
185
|
-
throw new Error(`Unknown slashing proposer type: ${proposerType}`);
|
|
329
|
+
if (proposerAddress.isZero()) {
|
|
330
|
+
return undefined;
|
|
186
331
|
}
|
|
332
|
+
|
|
333
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
187
334
|
}
|
|
188
335
|
|
|
189
336
|
@memoize
|
|
190
|
-
getL1StartBlock() {
|
|
337
|
+
getL1StartBlock(): Promise<bigint> {
|
|
191
338
|
return this.rollup.read.L1_BLOCK_AT_GENESIS();
|
|
192
339
|
}
|
|
193
340
|
|
|
194
341
|
@memoize
|
|
195
|
-
getL1GenesisTime() {
|
|
342
|
+
getL1GenesisTime(): Promise<bigint> {
|
|
196
343
|
return this.rollup.read.getGenesisTime();
|
|
197
344
|
}
|
|
198
345
|
|
|
199
346
|
@memoize
|
|
200
|
-
getProofSubmissionEpochs() {
|
|
201
|
-
return this.rollup.read.getProofSubmissionEpochs();
|
|
347
|
+
async getProofSubmissionEpochs(): Promise<number> {
|
|
348
|
+
return Number(await this.rollup.read.getProofSubmissionEpochs());
|
|
202
349
|
}
|
|
203
350
|
|
|
204
351
|
@memoize
|
|
205
|
-
getEpochDuration() {
|
|
206
|
-
return this.rollup.read.getEpochDuration();
|
|
352
|
+
async getEpochDuration(): Promise<number> {
|
|
353
|
+
return Number(await this.rollup.read.getEpochDuration());
|
|
207
354
|
}
|
|
208
355
|
|
|
209
356
|
@memoize
|
|
210
|
-
getSlotDuration() {
|
|
211
|
-
return this.rollup.read.getSlotDuration();
|
|
357
|
+
async getSlotDuration(): Promise<number> {
|
|
358
|
+
return Number(await this.rollup.read.getSlotDuration());
|
|
212
359
|
}
|
|
213
360
|
|
|
214
361
|
@memoize
|
|
215
|
-
getTargetCommitteeSize() {
|
|
216
|
-
return this.rollup.read.getTargetCommitteeSize();
|
|
362
|
+
async getTargetCommitteeSize(): Promise<number> {
|
|
363
|
+
return Number(await this.rollup.read.getTargetCommitteeSize());
|
|
217
364
|
}
|
|
218
365
|
|
|
219
366
|
@memoize
|
|
220
|
-
getEjectionThreshold() {
|
|
367
|
+
getEjectionThreshold(): Promise<bigint> {
|
|
221
368
|
return this.rollup.read.getEjectionThreshold();
|
|
222
369
|
}
|
|
223
370
|
|
|
224
371
|
@memoize
|
|
225
|
-
getLocalEjectionThreshold() {
|
|
372
|
+
getLocalEjectionThreshold(): Promise<bigint> {
|
|
226
373
|
return this.rollup.read.getLocalEjectionThreshold();
|
|
227
374
|
}
|
|
228
375
|
|
|
229
376
|
@memoize
|
|
230
|
-
|
|
231
|
-
return this.rollup.read.
|
|
377
|
+
async getLagInEpochsForValidatorSet(): Promise<number> {
|
|
378
|
+
return Number(await this.rollup.read.getLagInEpochsForValidatorSet());
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
@memoize
|
|
382
|
+
async getLagInEpochsForRandao(): Promise<number> {
|
|
383
|
+
return Number(await this.rollup.read.getLagInEpochsForRandao());
|
|
232
384
|
}
|
|
233
385
|
|
|
234
386
|
@memoize
|
|
235
|
-
getActivationThreshold() {
|
|
387
|
+
getActivationThreshold(): Promise<bigint> {
|
|
236
388
|
return this.rollup.read.getActivationThreshold();
|
|
237
389
|
}
|
|
238
390
|
|
|
239
391
|
@memoize
|
|
240
|
-
getExitDelay() {
|
|
241
|
-
return this.rollup.read.getExitDelay();
|
|
392
|
+
async getExitDelay(): Promise<number> {
|
|
393
|
+
return Number(await this.rollup.read.getExitDelay());
|
|
242
394
|
}
|
|
243
395
|
|
|
244
396
|
@memoize
|
|
245
|
-
getManaTarget() {
|
|
397
|
+
getManaTarget(): Promise<bigint> {
|
|
246
398
|
return this.rollup.read.getManaTarget();
|
|
247
399
|
}
|
|
248
400
|
|
|
249
401
|
@memoize
|
|
250
|
-
getProvingCostPerMana() {
|
|
402
|
+
getProvingCostPerMana(): Promise<bigint> {
|
|
251
403
|
return this.rollup.read.getProvingCostPerManaInEth();
|
|
252
404
|
}
|
|
253
405
|
|
|
254
406
|
@memoize
|
|
255
|
-
getProvingCostPerManaInFeeAsset() {
|
|
407
|
+
getProvingCostPerManaInFeeAsset(): Promise<bigint> {
|
|
256
408
|
return this.rollup.read.getProvingCostPerManaInFeeAsset();
|
|
257
409
|
}
|
|
258
410
|
|
|
259
411
|
@memoize
|
|
260
|
-
getManaLimit() {
|
|
412
|
+
getManaLimit(): Promise<bigint> {
|
|
261
413
|
return this.rollup.read.getManaLimit();
|
|
262
414
|
}
|
|
263
415
|
|
|
264
416
|
@memoize
|
|
265
|
-
getVersion() {
|
|
417
|
+
getVersion(): Promise<bigint> {
|
|
266
418
|
return this.rollup.read.getVersion();
|
|
267
419
|
}
|
|
268
420
|
|
|
269
421
|
@memoize
|
|
270
|
-
async getGenesisArchiveTreeRoot(): Promise
|
|
271
|
-
return await this.rollup.read.archiveAt([0n]);
|
|
422
|
+
async getGenesisArchiveTreeRoot(): Promise<Fr> {
|
|
423
|
+
return Fr.fromString(await this.rollup.read.archiveAt([0n]));
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
@memoize
|
|
427
|
+
async getVkTreeRoot(): Promise<Fr> {
|
|
428
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 3n;
|
|
429
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
430
|
+
return Fr.fromString(value ?? '0x0');
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
@memoize
|
|
434
|
+
async getProtocolContractsHash(): Promise<Fr> {
|
|
435
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 4n;
|
|
436
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
437
|
+
return Fr.fromString(value ?? '0x0');
|
|
272
438
|
}
|
|
273
439
|
|
|
274
440
|
/**
|
|
@@ -283,44 +449,115 @@ export class RollupContract {
|
|
|
283
449
|
slotDuration: number;
|
|
284
450
|
epochDuration: number;
|
|
285
451
|
proofSubmissionEpochs: number;
|
|
452
|
+
targetCommitteeSize: number;
|
|
453
|
+
rollupManaLimit: number;
|
|
286
454
|
}> {
|
|
287
|
-
const [
|
|
455
|
+
const [
|
|
456
|
+
l1StartBlock,
|
|
457
|
+
l1GenesisTime,
|
|
458
|
+
slotDuration,
|
|
459
|
+
epochDuration,
|
|
460
|
+
proofSubmissionEpochs,
|
|
461
|
+
targetCommitteeSize,
|
|
462
|
+
rollupManaLimit,
|
|
463
|
+
] = await Promise.all([
|
|
288
464
|
this.getL1StartBlock(),
|
|
289
465
|
this.getL1GenesisTime(),
|
|
290
466
|
this.getSlotDuration(),
|
|
291
467
|
this.getEpochDuration(),
|
|
292
468
|
this.getProofSubmissionEpochs(),
|
|
469
|
+
this.getTargetCommitteeSize(),
|
|
470
|
+
this.getManaLimit(),
|
|
293
471
|
]);
|
|
294
472
|
return {
|
|
295
473
|
l1StartBlock,
|
|
296
474
|
l1GenesisTime,
|
|
297
|
-
slotDuration
|
|
475
|
+
slotDuration,
|
|
298
476
|
epochDuration: Number(epochDuration),
|
|
299
477
|
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
478
|
+
targetCommitteeSize,
|
|
479
|
+
rollupManaLimit: Number(rollupManaLimit),
|
|
300
480
|
};
|
|
301
481
|
}
|
|
302
482
|
|
|
303
|
-
getSlasherAddress() {
|
|
304
|
-
return this.rollup.read.getSlasher();
|
|
483
|
+
async getSlasherAddress(): Promise<EthAddress> {
|
|
484
|
+
return EthAddress.fromString(await this.rollup.read.getSlasher());
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Returns the configured escape hatch contract address, or zero if disabled.
|
|
489
|
+
*/
|
|
490
|
+
async getEscapeHatchAddress(): Promise<EthAddress> {
|
|
491
|
+
return EthAddress.fromString(await this.rollup.read.getEscapeHatch());
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
private async getEscapeHatchContract(): Promise<
|
|
495
|
+
GetContractReturnType<typeof EscapeHatchAbi, ViemClient> | undefined
|
|
496
|
+
> {
|
|
497
|
+
const escapeHatchAddress = await this.getEscapeHatchAddress();
|
|
498
|
+
if (escapeHatchAddress.isZero()) {
|
|
499
|
+
return undefined;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Cache the viem contract wrapper since it will be used frequently.
|
|
503
|
+
if (!this.cachedEscapeHatch || !this.cachedEscapeHatch.address.equals(escapeHatchAddress)) {
|
|
504
|
+
this.cachedEscapeHatch = {
|
|
505
|
+
address: escapeHatchAddress,
|
|
506
|
+
contract: getContract({
|
|
507
|
+
address: escapeHatchAddress.toString(),
|
|
508
|
+
abi: EscapeHatchAbi,
|
|
509
|
+
client: this.client,
|
|
510
|
+
}),
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return this.cachedEscapeHatch.contract;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Returns whether the escape hatch is open for the given epoch.
|
|
519
|
+
* If escape hatch is not configured, returns false.
|
|
520
|
+
*
|
|
521
|
+
* This function is intentionally defensive: any failure to query the escape hatch
|
|
522
|
+
* (RPC issues, transient errors, etc.) is treated as "closed" to avoid callers
|
|
523
|
+
* needing to sprinkle try/catch everywhere.
|
|
524
|
+
*/
|
|
525
|
+
async isEscapeHatchOpen(epoch: EpochNumber): Promise<boolean> {
|
|
526
|
+
try {
|
|
527
|
+
const escapeHatch = await this.getEscapeHatchContract();
|
|
528
|
+
if (!escapeHatch) {
|
|
529
|
+
return false;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
|
|
533
|
+
return isOpen;
|
|
534
|
+
} catch (err) {
|
|
535
|
+
this.logger.warn('isEscapeHatchOpen failed (treating as closed); RPC or contract error may cause liveness risk', {
|
|
536
|
+
epoch: Number(epoch),
|
|
537
|
+
error: err,
|
|
538
|
+
});
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
305
541
|
}
|
|
306
542
|
|
|
307
543
|
/**
|
|
308
544
|
* Returns a SlasherContract instance for interacting with the slasher contract.
|
|
309
545
|
*/
|
|
310
546
|
async getSlasherContract(): Promise<SlasherContract | undefined> {
|
|
311
|
-
const slasherAddress =
|
|
547
|
+
const slasherAddress = await this.getSlasherAddress();
|
|
312
548
|
if (slasherAddress.isZero()) {
|
|
313
549
|
return undefined;
|
|
314
550
|
}
|
|
315
551
|
return new SlasherContract(this.client, slasherAddress);
|
|
316
552
|
}
|
|
317
553
|
|
|
318
|
-
getOwner() {
|
|
319
|
-
return this.rollup.read.owner();
|
|
554
|
+
async getOwner(): Promise<EthAddress> {
|
|
555
|
+
return EthAddress.fromString(await this.rollup.read.owner());
|
|
320
556
|
}
|
|
321
557
|
|
|
322
|
-
getActiveAttesterCount() {
|
|
323
|
-
|
|
558
|
+
async getActiveAttesterCount(options?: { blockNumber?: bigint }): Promise<number> {
|
|
559
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
560
|
+
return Number(await this.rollup.read.getActiveAttesterCount(options));
|
|
324
561
|
}
|
|
325
562
|
|
|
326
563
|
public async getSlashingProposerAddress() {
|
|
@@ -331,31 +568,50 @@ export class RollupContract {
|
|
|
331
568
|
return await slasher.getProposer();
|
|
332
569
|
}
|
|
333
570
|
|
|
334
|
-
|
|
335
|
-
return this.rollup.read.
|
|
571
|
+
getCheckpointReward(): Promise<bigint> {
|
|
572
|
+
return this.rollup.read.getCheckpointReward();
|
|
336
573
|
}
|
|
337
574
|
|
|
338
|
-
|
|
339
|
-
|
|
575
|
+
async getCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
576
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
577
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber(options));
|
|
340
578
|
}
|
|
341
579
|
|
|
342
|
-
|
|
343
|
-
|
|
580
|
+
async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
581
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
582
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
344
583
|
}
|
|
345
584
|
|
|
346
|
-
getSlotNumber() {
|
|
347
|
-
|
|
585
|
+
async getSlotNumber(options?: { blockNumber?: bigint }): Promise<SlotNumber> {
|
|
586
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
587
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot(options));
|
|
348
588
|
}
|
|
349
589
|
|
|
350
|
-
getL1FeesAt(timestamp: bigint) {
|
|
351
|
-
|
|
590
|
+
async getL1FeesAt(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<L1FeeData> {
|
|
591
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
592
|
+
const result = await this.rollup.read.getL1FeesAt([timestamp], options);
|
|
593
|
+
return {
|
|
594
|
+
baseFee: result.baseFee,
|
|
595
|
+
blobFee: result.blobFee,
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
async getFeeHeader(checkpointNumber: bigint): Promise<FeeHeader> {
|
|
600
|
+
const result = await this.rollup.read.getFeeHeader([checkpointNumber]);
|
|
601
|
+
return {
|
|
602
|
+
excessMana: result.excessMana,
|
|
603
|
+
manaUsed: result.manaUsed,
|
|
604
|
+
ethPerFeeAsset: result.ethPerFeeAsset,
|
|
605
|
+
congestionCost: result.congestionCost,
|
|
606
|
+
proverCost: result.proverCost,
|
|
607
|
+
};
|
|
352
608
|
}
|
|
353
609
|
|
|
354
|
-
|
|
355
|
-
return this.rollup.read.
|
|
610
|
+
getEthPerFeeAsset(): Promise<bigint> {
|
|
611
|
+
return this.rollup.read.getEthPerFeeAsset();
|
|
356
612
|
}
|
|
357
613
|
|
|
358
|
-
async getCommitteeAt(timestamp: bigint): Promise<
|
|
614
|
+
async getCommitteeAt(timestamp: bigint): Promise<EthAddress[] | undefined> {
|
|
359
615
|
const { result } = await this.client
|
|
360
616
|
.simulateContract({
|
|
361
617
|
address: this.address,
|
|
@@ -364,28 +620,28 @@ export class RollupContract {
|
|
|
364
620
|
args: [timestamp],
|
|
365
621
|
})
|
|
366
622
|
.catch(e => {
|
|
367
|
-
if (e
|
|
623
|
+
if (isValidatorSelectionError(e, INSUFFICIENT_VALIDATOR_SET_SIZE_ERROR)) {
|
|
368
624
|
return { result: undefined };
|
|
369
625
|
}
|
|
370
626
|
throw e;
|
|
371
627
|
});
|
|
372
628
|
|
|
373
|
-
return result;
|
|
629
|
+
return result ? result.map(addr => EthAddress.fromString(addr)) : undefined;
|
|
374
630
|
}
|
|
375
631
|
|
|
376
|
-
getSampleSeedAt(timestamp: bigint) {
|
|
377
|
-
return this.rollup.read.getSampleSeedAt([timestamp]);
|
|
632
|
+
async getSampleSeedAt(timestamp: bigint): Promise<Buffer32> {
|
|
633
|
+
return Buffer32.fromBigInt(await this.rollup.read.getSampleSeedAt([timestamp]));
|
|
378
634
|
}
|
|
379
635
|
|
|
380
|
-
getCurrentSampleSeed() {
|
|
381
|
-
return this.rollup.read.getCurrentSampleSeed();
|
|
636
|
+
async getCurrentSampleSeed(): Promise<Buffer32> {
|
|
637
|
+
return Buffer32.fromBigInt(await this.rollup.read.getCurrentSampleSeed());
|
|
382
638
|
}
|
|
383
639
|
|
|
384
|
-
getCurrentEpoch() {
|
|
385
|
-
return this.rollup.read.getCurrentEpoch();
|
|
640
|
+
async getCurrentEpoch(): Promise<EpochNumber> {
|
|
641
|
+
return EpochNumber.fromBigInt(await this.rollup.read.getCurrentEpoch());
|
|
386
642
|
}
|
|
387
643
|
|
|
388
|
-
async getCurrentEpochCommittee(): Promise<
|
|
644
|
+
async getCurrentEpochCommittee(): Promise<EthAddress[] | undefined> {
|
|
389
645
|
const { result } = await this.client
|
|
390
646
|
.simulateContract({
|
|
391
647
|
address: this.address,
|
|
@@ -394,16 +650,16 @@ export class RollupContract {
|
|
|
394
650
|
args: [],
|
|
395
651
|
})
|
|
396
652
|
.catch(e => {
|
|
397
|
-
if (e
|
|
653
|
+
if (isValidatorSelectionError(e, INSUFFICIENT_VALIDATOR_SET_SIZE_ERROR)) {
|
|
398
654
|
return { result: undefined };
|
|
399
655
|
}
|
|
400
656
|
throw e;
|
|
401
657
|
});
|
|
402
658
|
|
|
403
|
-
return result;
|
|
659
|
+
return result ? result.map(addr => EthAddress.fromString(addr)) : undefined;
|
|
404
660
|
}
|
|
405
661
|
|
|
406
|
-
async getCurrentProposer() {
|
|
662
|
+
async getCurrentProposer(): Promise<EthAddress> {
|
|
407
663
|
const { result } = await this.client.simulateContract({
|
|
408
664
|
address: this.address,
|
|
409
665
|
abi: RollupAbi,
|
|
@@ -411,10 +667,10 @@ export class RollupContract {
|
|
|
411
667
|
args: [],
|
|
412
668
|
});
|
|
413
669
|
|
|
414
|
-
return result;
|
|
670
|
+
return EthAddress.fromString(result);
|
|
415
671
|
}
|
|
416
672
|
|
|
417
|
-
async getProposerAt(timestamp: bigint) {
|
|
673
|
+
async getProposerAt(timestamp: bigint): Promise<EthAddress> {
|
|
418
674
|
const { result } = await this.client.simulateContract({
|
|
419
675
|
address: this.address,
|
|
420
676
|
abi: RollupAbi,
|
|
@@ -422,39 +678,98 @@ export class RollupContract {
|
|
|
422
678
|
args: [timestamp],
|
|
423
679
|
});
|
|
424
680
|
|
|
425
|
-
return result;
|
|
681
|
+
return EthAddress.fromString(result);
|
|
426
682
|
}
|
|
427
683
|
|
|
428
|
-
|
|
429
|
-
|
|
684
|
+
async getCheckpoint(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise<CheckpointLog> {
|
|
685
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
686
|
+
const result = await this.rollup.read.getCheckpoint([BigInt(checkpointNumber)], options);
|
|
687
|
+
return {
|
|
688
|
+
archive: Fr.fromString(result.archive),
|
|
689
|
+
headerHash: Buffer32.fromString(result.headerHash),
|
|
690
|
+
blobCommitmentsHash: Buffer32.fromString(result.blobCommitmentsHash),
|
|
691
|
+
attestationsHash: Buffer32.fromString(result.attestationsHash),
|
|
692
|
+
payloadDigest: Buffer32.fromString(result.payloadDigest),
|
|
693
|
+
slotNumber: SlotNumber.fromBigInt(result.slotNumber),
|
|
694
|
+
feeHeader: {
|
|
695
|
+
excessMana: result.feeHeader.excessMana,
|
|
696
|
+
manaUsed: result.feeHeader.manaUsed,
|
|
697
|
+
ethPerFeeAsset: result.feeHeader.ethPerFeeAsset,
|
|
698
|
+
congestionCost: result.feeHeader.congestionCost,
|
|
699
|
+
proverCost: result.feeHeader.proverCost,
|
|
700
|
+
},
|
|
701
|
+
};
|
|
430
702
|
}
|
|
431
703
|
|
|
432
|
-
|
|
433
|
-
|
|
704
|
+
/** Returns the pending checkpoint from the rollup contract */
|
|
705
|
+
getPendingCheckpoint() {
|
|
706
|
+
// We retry because of race conditions during prunes: we may get a pending checkpoint number which is immediately
|
|
707
|
+
// reorged out due to a prune happening, causing the subsequent getCheckpoint call to fail. So we try again in that case.
|
|
708
|
+
return retry(
|
|
709
|
+
async () => {
|
|
710
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber();
|
|
711
|
+
const pendingCheckpoint = await this.getCheckpoint(pendingCheckpointNumber);
|
|
712
|
+
return pendingCheckpoint;
|
|
713
|
+
},
|
|
714
|
+
'getting pending checkpoint',
|
|
715
|
+
makeBackoff([0.5, 0.5, 0.5]),
|
|
716
|
+
);
|
|
434
717
|
}
|
|
435
718
|
|
|
436
|
-
|
|
437
|
-
|
|
719
|
+
/**
|
|
720
|
+
* Returns the effective pending checkpoint, accounting for potential prunes.
|
|
721
|
+
* When a prune can happen, the L1 contract uses the proven checkpoint instead of the pending one.
|
|
722
|
+
* This mirrors the behavior of getEffectivePendingCheckpointNumber in STFLib.sol.
|
|
723
|
+
* @param atTimestamp - The timestamp to evaluate pruneability at. Defaults to the current L1 block timestamp.
|
|
724
|
+
* @param options - Optional L1 block number to pin the queries to.
|
|
725
|
+
*/
|
|
726
|
+
getEffectivePendingCheckpoint(atTimestamp?: bigint, options?: { blockNumber?: bigint }) {
|
|
727
|
+
return retry(
|
|
728
|
+
async () => {
|
|
729
|
+
const timestamp = atTimestamp ?? (await this.client.getBlock()).timestamp;
|
|
730
|
+
const canPrune = await this.canPruneAtTime(timestamp, options);
|
|
731
|
+
if (canPrune) {
|
|
732
|
+
const provenCheckpointNumber = await this.getProvenCheckpointNumber(options);
|
|
733
|
+
return await this.getCheckpoint(provenCheckpointNumber, options);
|
|
734
|
+
}
|
|
735
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber(options);
|
|
736
|
+
return await this.getCheckpoint(pendingCheckpointNumber, options);
|
|
737
|
+
},
|
|
738
|
+
'getting effective pending checkpoint',
|
|
739
|
+
makeBackoff([0.5, 0.5, 0.5]),
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
async getTips(): Promise<{ pending: CheckpointNumber; proven: CheckpointNumber }> {
|
|
744
|
+
const { pending, proven } = await this.rollup.read.getTips();
|
|
745
|
+
return {
|
|
746
|
+
pending: CheckpointNumber.fromBigInt(pending),
|
|
747
|
+
proven: CheckpointNumber.fromBigInt(proven),
|
|
748
|
+
};
|
|
438
749
|
}
|
|
439
750
|
|
|
440
|
-
|
|
441
|
-
return this.rollup.read.
|
|
751
|
+
getTimestampForSlot(slot: SlotNumber): Promise<bigint> {
|
|
752
|
+
return this.rollup.read.getTimestampForSlot([BigInt(slot)]);
|
|
442
753
|
}
|
|
443
754
|
|
|
444
|
-
|
|
445
|
-
return this.rollup.read.
|
|
755
|
+
async getEntryQueueLength(): Promise<number> {
|
|
756
|
+
return Number(await this.rollup.read.getEntryQueueLength());
|
|
446
757
|
}
|
|
447
758
|
|
|
448
|
-
|
|
449
|
-
return this.rollup.read.
|
|
759
|
+
async getAvailableValidatorFlushes(): Promise<number> {
|
|
760
|
+
return Number(await this.rollup.read.getAvailableValidatorFlushes());
|
|
450
761
|
}
|
|
451
762
|
|
|
452
|
-
|
|
453
|
-
return this.rollup.read.
|
|
763
|
+
async getNextFlushableEpoch(): Promise<EpochNumber> {
|
|
764
|
+
return EpochNumber.fromBigInt(await this.rollup.read.getNextFlushableEpoch());
|
|
454
765
|
}
|
|
455
766
|
|
|
456
|
-
|
|
457
|
-
return this.rollup.read.
|
|
767
|
+
async getCurrentEpochNumber(): Promise<EpochNumber> {
|
|
768
|
+
return EpochNumber.fromBigInt(await this.rollup.read.getCurrentEpoch());
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
async getEpochNumberForCheckpoint(checkpointNumber: CheckpointNumber): Promise<EpochNumber> {
|
|
772
|
+
return EpochNumber.fromBigInt(await this.rollup.read.getEpochForCheckpoint([BigInt(checkpointNumber)]));
|
|
458
773
|
}
|
|
459
774
|
|
|
460
775
|
async getRollupAddresses(): Promise<L1RollupContractAddresses> {
|
|
@@ -494,14 +809,15 @@ export class RollupContract {
|
|
|
494
809
|
return EthAddress.fromString(await this.rollup.read.getFeeAssetPortal());
|
|
495
810
|
}
|
|
496
811
|
|
|
497
|
-
public async getEpochNumberForSlotNumber(slotNumber:
|
|
498
|
-
return await this.rollup.read.getEpochAtSlot([slotNumber]);
|
|
812
|
+
public async getEpochNumberForSlotNumber(slotNumber: SlotNumber): Promise<EpochNumber> {
|
|
813
|
+
return EpochNumber.fromBigInt(await this.rollup.read.getEpochAtSlot([BigInt(slotNumber)]));
|
|
499
814
|
}
|
|
500
815
|
|
|
501
|
-
getEpochProofPublicInputs(
|
|
502
|
-
args: readonly [bigint, bigint, EpochProofPublicInputArgs, readonly
|
|
503
|
-
) {
|
|
504
|
-
|
|
816
|
+
async getEpochProofPublicInputs(
|
|
817
|
+
args: readonly [bigint, bigint, EpochProofPublicInputArgs, readonly ViemHeader[], `0x${string}`],
|
|
818
|
+
): Promise<Fr[]> {
|
|
819
|
+
const result = await this.rollup.read.getEpochProofPublicInputs(args);
|
|
820
|
+
return result.map(Fr.fromString);
|
|
505
821
|
}
|
|
506
822
|
|
|
507
823
|
public async validateHeader(
|
|
@@ -538,53 +854,68 @@ export class RollupContract {
|
|
|
538
854
|
* @dev Throws if unable to propose
|
|
539
855
|
*
|
|
540
856
|
* @param archive - The archive that we expect to be current state
|
|
541
|
-
* @return [slot,
|
|
857
|
+
* @return [slot, checkpointNumber, timeOfNextL1Slot] - If you can propose, the L2 slot number, checkpoint number and
|
|
858
|
+
* timestamp of the next L1 block
|
|
542
859
|
* @throws otherwise
|
|
543
860
|
*/
|
|
544
|
-
public async
|
|
861
|
+
public async canProposeAt(
|
|
545
862
|
archive: Buffer,
|
|
546
863
|
account: `0x${string}` | Account,
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
): Promise<{ slot:
|
|
550
|
-
|
|
551
|
-
slotDuration = BigInt(slotDuration);
|
|
552
|
-
}
|
|
553
|
-
const latestBlock = await this.client.getBlock();
|
|
554
|
-
const timeOfNextL1Slot = latestBlock.timestamp + slotDuration;
|
|
864
|
+
timestamp: bigint,
|
|
865
|
+
stateOverride: StateOverride = [],
|
|
866
|
+
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
867
|
+
const timeOfNextL1Slot = timestamp;
|
|
555
868
|
const who = typeof account === 'string' ? account : account.address;
|
|
556
869
|
|
|
557
870
|
try {
|
|
558
871
|
const {
|
|
559
|
-
result: [slot,
|
|
872
|
+
result: [slot, checkpointNumber],
|
|
560
873
|
} = await this.client.simulateContract({
|
|
561
874
|
address: this.address,
|
|
562
875
|
abi: RollupAbi,
|
|
563
876
|
functionName: 'canProposeAtTime',
|
|
564
877
|
args: [timeOfNextL1Slot, `0x${archive.toString('hex')}`, who],
|
|
565
878
|
account,
|
|
566
|
-
stateOverride
|
|
879
|
+
stateOverride,
|
|
567
880
|
});
|
|
568
881
|
|
|
569
|
-
return {
|
|
882
|
+
return {
|
|
883
|
+
slot: SlotNumber.fromBigInt(slot),
|
|
884
|
+
checkpointNumber: CheckpointNumber.fromBigInt(checkpointNumber),
|
|
885
|
+
timeOfNextL1Slot,
|
|
886
|
+
};
|
|
570
887
|
} catch (err: unknown) {
|
|
571
888
|
throw formatViemError(err);
|
|
572
889
|
}
|
|
573
890
|
}
|
|
574
891
|
|
|
575
892
|
/**
|
|
576
|
-
* Returns a state override that sets the pending
|
|
577
|
-
*
|
|
578
|
-
*
|
|
893
|
+
* Returns a state override that sets the pending and/or proven checkpoint numbers. Useful for simulations.
|
|
894
|
+
* Both values share a single storage slot (pending in the upper 128 bits, proven in the lower 128 bits), so
|
|
895
|
+
* a single combined override is emitted to avoid the second state-diff clobbering the first. The current live
|
|
896
|
+
* value is read once to preserve any half not being overridden. Returns an empty override if neither is set.
|
|
897
|
+
*
|
|
898
|
+
* Throws if the resulting `proven > pending`, which would crash the simulation: `STFLib.canPruneAtTime` calls
|
|
899
|
+
* `getEpochForCheckpoint(proven + 1)` whenever `pending != proven`, and that asserts `_n <= tips.pending`.
|
|
579
900
|
*/
|
|
580
|
-
public async
|
|
581
|
-
|
|
901
|
+
public async makeChainTipsOverride(override: {
|
|
902
|
+
pending?: CheckpointNumber;
|
|
903
|
+
proven?: CheckpointNumber;
|
|
904
|
+
}): Promise<StateOverride> {
|
|
905
|
+
if (override.pending === undefined && override.proven === undefined) {
|
|
582
906
|
return [];
|
|
583
907
|
}
|
|
584
908
|
const slot = RollupContract.stfStorageSlot;
|
|
585
909
|
const currentValue = await this.client.getStorageAt({ address: this.address, slot });
|
|
586
|
-
const
|
|
587
|
-
const
|
|
910
|
+
const currentRaw = currentValue ? hexToBigInt(currentValue) : 0n;
|
|
911
|
+
const currentPending = currentRaw >> 128n;
|
|
912
|
+
const currentProven = currentRaw & ((1n << 128n) - 1n);
|
|
913
|
+
const newPending = override.pending !== undefined ? BigInt(override.pending) : currentPending;
|
|
914
|
+
const newProven = override.proven !== undefined ? BigInt(override.proven) : currentProven;
|
|
915
|
+
if (newProven > newPending) {
|
|
916
|
+
throw new Error(`Invalid chain tips override: proven (${newProven}) > pending (${newPending})`);
|
|
917
|
+
}
|
|
918
|
+
const newValue = (newPending << 128n) | newProven;
|
|
588
919
|
return [
|
|
589
920
|
{
|
|
590
921
|
address: this.address,
|
|
@@ -593,20 +924,183 @@ export class RollupContract {
|
|
|
593
924
|
];
|
|
594
925
|
}
|
|
595
926
|
|
|
927
|
+
/**
|
|
928
|
+
* Returns a state override that patches `tempCheckpointLogs[checkpointNumber]` with every field that
|
|
929
|
+
* the L1 contract reads during `propose()` for the checkpoint that builds on top of it (proposer
|
|
930
|
+
* pipelining simulation). Mirrors the writes done by `ProposeLib.addTempCheckpointLog`.
|
|
931
|
+
*
|
|
932
|
+
* `blobCommitmentsHash` and `attestationsHash` are intentionally not exposed here — the propose path
|
|
933
|
+
* never asserts against them, so leaving them at storage zero is harmless.
|
|
934
|
+
*/
|
|
935
|
+
public async makeTempCheckpointLogOverride(
|
|
936
|
+
checkpointNumber: CheckpointNumber,
|
|
937
|
+
fields: TempCheckpointLogOverrideFields,
|
|
938
|
+
): Promise<StateOverride> {
|
|
939
|
+
const constants = await this.getRollupConstants();
|
|
940
|
+
const slotAt = (field: TempCheckpointLogField) =>
|
|
941
|
+
`0x${this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, constants).toString(16).padStart(64, '0')}` as const;
|
|
942
|
+
const word = (v: bigint) => `0x${v.toString(16).padStart(64, '0')}` as const;
|
|
943
|
+
|
|
944
|
+
const stateDiff: { slot: `0x${string}`; value: `0x${string}` }[] = [];
|
|
945
|
+
|
|
946
|
+
if (fields.headerHash) {
|
|
947
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.HeaderHash), value: fields.headerHash.toString() });
|
|
948
|
+
}
|
|
949
|
+
if (fields.outHash) {
|
|
950
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.OutHash), value: fields.outHash.toString() });
|
|
951
|
+
}
|
|
952
|
+
if (fields.payloadDigest) {
|
|
953
|
+
stateDiff.push({
|
|
954
|
+
slot: slotAt(TempCheckpointLogField.PayloadDigest),
|
|
955
|
+
value: fields.payloadDigest.toString() as `0x${string}`,
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
if (fields.slotNumber !== undefined) {
|
|
959
|
+
// CompressedSlot is uint32 on L1 (SafeCast.toUint32 reverts on overflow). Match that behavior here
|
|
960
|
+
// so a malformed override surfaces immediately rather than silently truncating into a wrong slot.
|
|
961
|
+
const slotNumber = BigInt(fields.slotNumber);
|
|
962
|
+
if (slotNumber < 0n || slotNumber > 0xffffffffn) {
|
|
963
|
+
throw new Error(`slotNumber ${slotNumber} does not fit in uint32`);
|
|
964
|
+
}
|
|
965
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.SlotNumber), value: word(slotNumber) });
|
|
966
|
+
}
|
|
967
|
+
if (fields.feeHeader) {
|
|
968
|
+
stateDiff.push({
|
|
969
|
+
slot: slotAt(TempCheckpointLogField.FeeHeader),
|
|
970
|
+
value: word(RollupContract.compressFeeHeader(fields.feeHeader)),
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (stateDiff.length === 0) {
|
|
975
|
+
return [];
|
|
976
|
+
}
|
|
977
|
+
return [{ address: this.address, stateDiff }];
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Returns a state override that sets archives[checkpointNumber] to the given archive value.
|
|
982
|
+
* Used when simulating a canProposeAtTime call where the local archive differs from L1
|
|
983
|
+
* (e.g. pipelining where the parent checkpoint hasn't landed on L1 yet).
|
|
984
|
+
*/
|
|
985
|
+
public makeArchiveOverride(checkpointNumber: CheckpointNumber, archive: Fr): StateOverride {
|
|
986
|
+
const archivesMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 1n;
|
|
987
|
+
const archiveSlot = hexToBigInt(
|
|
988
|
+
keccak256(
|
|
989
|
+
encodeAbiParameters(
|
|
990
|
+
[{ type: 'uint256' }, { type: 'uint256' }],
|
|
991
|
+
[BigInt(checkpointNumber), archivesMappingBase],
|
|
992
|
+
),
|
|
993
|
+
),
|
|
994
|
+
);
|
|
995
|
+
return [
|
|
996
|
+
{
|
|
997
|
+
address: this.address,
|
|
998
|
+
stateDiff: [
|
|
999
|
+
{
|
|
1000
|
+
slot: `0x${archiveSlot.toString(16).padStart(64, '0')}`,
|
|
1001
|
+
value: archive.toString(),
|
|
1002
|
+
},
|
|
1003
|
+
],
|
|
1004
|
+
},
|
|
1005
|
+
];
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/** Merges multiple StateOverride arrays, combining stateDiff entries for the same address. */
|
|
1009
|
+
public static mergeStateOverrides(...overrides: StateOverride[]): StateOverride {
|
|
1010
|
+
type StateDiffEntry = { slot: `0x${string}`; value: `0x${string}` };
|
|
1011
|
+
const byAddress = new Map<string, { address: `0x${string}`; balance?: bigint; stateDiff: StateDiffEntry[] }>();
|
|
1012
|
+
for (const override of overrides) {
|
|
1013
|
+
for (const entry of override) {
|
|
1014
|
+
const key = entry.address.toLowerCase();
|
|
1015
|
+
const existing = byAddress.get(key);
|
|
1016
|
+
if (existing) {
|
|
1017
|
+
existing.stateDiff.push(...(entry.stateDiff ?? []));
|
|
1018
|
+
if (entry.balance !== undefined) {
|
|
1019
|
+
existing.balance = entry.balance;
|
|
1020
|
+
}
|
|
1021
|
+
} else {
|
|
1022
|
+
byAddress.set(key, {
|
|
1023
|
+
address: entry.address,
|
|
1024
|
+
balance: entry.balance,
|
|
1025
|
+
stateDiff: [...(entry.stateDiff ?? [])],
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
return [...byAddress.values()];
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/** Compresses a FeeHeader into a uint256 matching FeeHeaderLib.compress() in FeeStructs.sol. */
|
|
1034
|
+
public static compressFeeHeader(feeHeader: FeeHeader): bigint {
|
|
1035
|
+
const MASK_48_BITS = (1n << 48n) - 1n;
|
|
1036
|
+
const MASK_64_BITS = (1n << 64n) - 1n;
|
|
1037
|
+
const MASK_63_BITS = (1n << 63n) - 1n;
|
|
1038
|
+
|
|
1039
|
+
let value = BigInt(feeHeader.manaUsed) & ((1n << 32n) - 1n); // bits [0:31]
|
|
1040
|
+
value |= (feeHeader.excessMana < MASK_48_BITS ? feeHeader.excessMana : MASK_48_BITS) << 32n; // bits [32:79]
|
|
1041
|
+
value |= (BigInt(feeHeader.ethPerFeeAsset) & MASK_48_BITS) << 80n; // bits [80:127]
|
|
1042
|
+
value |= (feeHeader.congestionCost < MASK_64_BITS ? feeHeader.congestionCost : MASK_64_BITS) << 128n; // bits [128:191]
|
|
1043
|
+
value |= (feeHeader.proverCost < MASK_63_BITS ? feeHeader.proverCost : MASK_63_BITS) << 192n; // bits [192:254]
|
|
1044
|
+
value |= 1n << 255n; // preheat flag
|
|
1045
|
+
return value;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/** Computes the fee header for a child checkpoint given parent fee header and child data.
|
|
1049
|
+
* Must stay in sync with Solidity FeeLib.sol (computeNewEthPerFeeAsset, clampedAdd). */
|
|
1050
|
+
public static computeChildFeeHeader(
|
|
1051
|
+
parentFeeHeader: FeeHeader,
|
|
1052
|
+
childManaUsed: bigint,
|
|
1053
|
+
feeAssetPriceModifier: bigint,
|
|
1054
|
+
manaTarget: bigint,
|
|
1055
|
+
): FeeHeader {
|
|
1056
|
+
const MIN_ETH_PER_FEE_ASSET = 100n;
|
|
1057
|
+
const MAX_ETH_PER_FEE_ASSET = 100_000_000_000_000n; // 1e14, matches FeeLib.sol
|
|
1058
|
+
|
|
1059
|
+
// excessMana = clampedAdd(parent.excessMana + parent.manaUsed, -manaTarget)
|
|
1060
|
+
const sum = parentFeeHeader.excessMana + parentFeeHeader.manaUsed;
|
|
1061
|
+
const excessMana = sum > manaTarget ? sum - manaTarget : 0n;
|
|
1062
|
+
|
|
1063
|
+
// ethPerFeeAsset = computeNewEthPerFeeAsset(max(parent.ethPerFeeAsset, MIN), modifier)
|
|
1064
|
+
const parentPrice =
|
|
1065
|
+
parentFeeHeader.ethPerFeeAsset > MIN_ETH_PER_FEE_ASSET ? parentFeeHeader.ethPerFeeAsset : MIN_ETH_PER_FEE_ASSET;
|
|
1066
|
+
let newPrice: bigint;
|
|
1067
|
+
if (feeAssetPriceModifier >= 0n) {
|
|
1068
|
+
newPrice = (parentPrice * (10_000n + feeAssetPriceModifier)) / 10_000n;
|
|
1069
|
+
} else {
|
|
1070
|
+
const absMod = -feeAssetPriceModifier;
|
|
1071
|
+
newPrice = (parentPrice * (10_000n - absMod)) / 10_000n;
|
|
1072
|
+
}
|
|
1073
|
+
if (newPrice < MIN_ETH_PER_FEE_ASSET) {
|
|
1074
|
+
newPrice = MIN_ETH_PER_FEE_ASSET;
|
|
1075
|
+
}
|
|
1076
|
+
if (newPrice > MAX_ETH_PER_FEE_ASSET) {
|
|
1077
|
+
newPrice = MAX_ETH_PER_FEE_ASSET;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
return {
|
|
1081
|
+
excessMana,
|
|
1082
|
+
manaUsed: childManaUsed,
|
|
1083
|
+
ethPerFeeAsset: newPrice,
|
|
1084
|
+
congestionCost: 0n,
|
|
1085
|
+
proverCost: 0n,
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
|
|
596
1089
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
597
1090
|
public buildInvalidateBadAttestationRequest(
|
|
598
|
-
|
|
1091
|
+
checkpointNumber: CheckpointNumber,
|
|
599
1092
|
attestationsAndSigners: ViemCommitteeAttestations,
|
|
600
1093
|
committee: EthAddress[],
|
|
601
1094
|
invalidIndex: number,
|
|
602
1095
|
): L1TxRequest {
|
|
603
1096
|
return {
|
|
604
1097
|
to: this.address,
|
|
1098
|
+
abi: RollupAbi,
|
|
605
1099
|
data: encodeFunctionData({
|
|
606
1100
|
abi: RollupAbi,
|
|
607
1101
|
functionName: 'invalidateBadAttestation',
|
|
608
1102
|
args: [
|
|
609
|
-
BigInt(
|
|
1103
|
+
BigInt(checkpointNumber),
|
|
610
1104
|
attestationsAndSigners,
|
|
611
1105
|
committee.map(addr => addr.toString()),
|
|
612
1106
|
BigInt(invalidIndex),
|
|
@@ -617,112 +1111,163 @@ export class RollupContract {
|
|
|
617
1111
|
|
|
618
1112
|
/** Creates a request to Rollup#invalidateInsufficientAttestations to be simulated or sent */
|
|
619
1113
|
public buildInvalidateInsufficientAttestationsRequest(
|
|
620
|
-
|
|
1114
|
+
checkpointNumber: CheckpointNumber,
|
|
621
1115
|
attestationsAndSigners: ViemCommitteeAttestations,
|
|
622
1116
|
committee: EthAddress[],
|
|
623
1117
|
): L1TxRequest {
|
|
624
1118
|
return {
|
|
625
1119
|
to: this.address,
|
|
1120
|
+
abi: RollupAbi,
|
|
626
1121
|
data: encodeFunctionData({
|
|
627
1122
|
abi: RollupAbi,
|
|
628
1123
|
functionName: 'invalidateInsufficientAttestations',
|
|
629
|
-
args: [BigInt(
|
|
1124
|
+
args: [BigInt(checkpointNumber), attestationsAndSigners, committee.map(addr => addr.toString())],
|
|
630
1125
|
}),
|
|
631
1126
|
};
|
|
632
1127
|
}
|
|
633
1128
|
|
|
634
1129
|
/** Calls getHasSubmitted directly. Returns whether the given prover has submitted a proof with the given length for the given epoch. */
|
|
635
|
-
public getHasSubmittedProof(epochNumber:
|
|
1130
|
+
public getHasSubmittedProof(epochNumber: EpochNumber, numberOfCheckpointsInEpoch: number, prover: Hex | EthAddress) {
|
|
636
1131
|
if (prover instanceof EthAddress) {
|
|
637
1132
|
prover = prover.toString();
|
|
638
1133
|
}
|
|
639
|
-
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(
|
|
1134
|
+
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]);
|
|
640
1135
|
}
|
|
641
1136
|
|
|
642
|
-
|
|
643
|
-
return this.rollup.read.
|
|
1137
|
+
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean, stateOverride?: StateOverride): Promise<bigint> {
|
|
1138
|
+
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset], { stateOverride });
|
|
644
1139
|
}
|
|
645
1140
|
|
|
646
|
-
|
|
647
|
-
|
|
1141
|
+
async getManaMinFeeComponentsAt(timestamp: bigint, inFeeAsset: boolean): Promise<ManaMinFeeComponents> {
|
|
1142
|
+
const result = await this.rollup.read.getManaMinFeeComponentsAt([timestamp, inFeeAsset]);
|
|
1143
|
+
return {
|
|
1144
|
+
sequencerCost: result.sequencerCost,
|
|
1145
|
+
proverCost: result.proverCost,
|
|
1146
|
+
congestionCost: result.congestionCost,
|
|
1147
|
+
congestionMultiplier: result.congestionMultiplier,
|
|
1148
|
+
};
|
|
648
1149
|
}
|
|
649
1150
|
|
|
650
|
-
async
|
|
1151
|
+
async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
|
|
1152
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getSlotAt([timestamp]));
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
async status(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise<RollupStatusResponse> {
|
|
651
1156
|
await checkBlockTag(options?.blockNumber, this.client);
|
|
652
|
-
|
|
1157
|
+
const result = await this.rollup.read.status([BigInt(checkpointNumber)], options);
|
|
1158
|
+
return {
|
|
1159
|
+
provenCheckpointNumber: CheckpointNumber.fromBigInt(result[0]),
|
|
1160
|
+
provenArchive: Fr.fromString(result[1]),
|
|
1161
|
+
pendingCheckpointNumber: CheckpointNumber.fromBigInt(result[2]),
|
|
1162
|
+
pendingArchive: Fr.fromString(result[3]),
|
|
1163
|
+
archiveOfMyCheckpoint: Fr.fromString(result[4]),
|
|
1164
|
+
};
|
|
653
1165
|
}
|
|
654
1166
|
|
|
655
|
-
async canPruneAtTime(timestamp: bigint, options?: { blockNumber?: bigint }) {
|
|
1167
|
+
async canPruneAtTime(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<boolean> {
|
|
656
1168
|
await checkBlockTag(options?.blockNumber, this.client);
|
|
657
1169
|
return this.rollup.read.canPruneAtTime([timestamp], options);
|
|
658
1170
|
}
|
|
659
1171
|
|
|
660
|
-
archive() {
|
|
661
|
-
return this.rollup.read.archive();
|
|
1172
|
+
async archive(): Promise<Fr> {
|
|
1173
|
+
return Fr.fromString(await this.rollup.read.archive());
|
|
662
1174
|
}
|
|
663
1175
|
|
|
664
|
-
archiveAt(
|
|
665
|
-
return this.rollup.read.archiveAt([
|
|
1176
|
+
async archiveAt(checkpointNumber: CheckpointNumber): Promise<Fr> {
|
|
1177
|
+
return Fr.fromString(await this.rollup.read.archiveAt([BigInt(checkpointNumber)]));
|
|
666
1178
|
}
|
|
667
1179
|
|
|
668
|
-
getSequencerRewards(address: Hex | EthAddress) {
|
|
1180
|
+
getSequencerRewards(address: Hex | EthAddress): Promise<bigint> {
|
|
669
1181
|
if (address instanceof EthAddress) {
|
|
670
1182
|
address = address.toString();
|
|
671
1183
|
}
|
|
672
1184
|
return this.rollup.read.getSequencerRewards([address]);
|
|
673
1185
|
}
|
|
674
1186
|
|
|
675
|
-
getSpecificProverRewardsForEpoch(epoch: bigint, prover: Hex | EthAddress) {
|
|
1187
|
+
getSpecificProverRewardsForEpoch(epoch: bigint, prover: Hex | EthAddress): Promise<bigint> {
|
|
676
1188
|
if (prover instanceof EthAddress) {
|
|
677
1189
|
prover = prover.toString();
|
|
678
1190
|
}
|
|
679
1191
|
return this.rollup.read.getSpecificProverRewardsForEpoch([epoch, prover]);
|
|
680
1192
|
}
|
|
681
1193
|
|
|
682
|
-
async getAttesters() {
|
|
683
|
-
|
|
1194
|
+
async getAttesters(timestamp?: bigint): Promise<EthAddress[]> {
|
|
1195
|
+
// Pin every read to a single L1 block so the attester count and the chunked index reads
|
|
1196
|
+
// observe a consistent set. Without this, the count and each chunk default to `latest` and
|
|
1197
|
+
// can straddle a block boundary (or reorg), yielding an inconsistent or truncated set.
|
|
1198
|
+
const block = await this.client.getBlock();
|
|
1199
|
+
const blockNumber = block.number ?? undefined;
|
|
1200
|
+
const ts = timestamp ?? block.timestamp;
|
|
1201
|
+
const attesterSize = await this.getActiveAttesterCount({ blockNumber });
|
|
684
1202
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
const indices = Array.from({ length: Number(attesterSize) }, (_, i) => BigInt(i));
|
|
1203
|
+
const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i));
|
|
688
1204
|
const chunks = chunk(indices, 1000);
|
|
689
1205
|
|
|
690
|
-
|
|
1206
|
+
const results = await Promise.all(
|
|
1207
|
+
chunks.map(chunk => gse.getAttestersFromIndicesAtTime(this.address, ts, chunk, { blockNumber })),
|
|
1208
|
+
);
|
|
1209
|
+
return results.flat().map(addr => EthAddress.fromString(addr));
|
|
691
1210
|
}
|
|
692
1211
|
|
|
693
|
-
getAttesterView(address: Hex | EthAddress) {
|
|
1212
|
+
async getAttesterView(address: Hex | EthAddress): Promise<AttesterView> {
|
|
694
1213
|
if (address instanceof EthAddress) {
|
|
695
1214
|
address = address.toString();
|
|
696
1215
|
}
|
|
697
|
-
|
|
1216
|
+
const result = await this.rollup.read.getAttesterView([address]);
|
|
1217
|
+
return {
|
|
1218
|
+
status: result.status as AttesterStatus,
|
|
1219
|
+
effectiveBalance: result.effectiveBalance,
|
|
1220
|
+
exit: {
|
|
1221
|
+
withdrawalId: result.exit.withdrawalId,
|
|
1222
|
+
amount: result.exit.amount,
|
|
1223
|
+
exitableAt: result.exit.exitableAt,
|
|
1224
|
+
recipientOrWithdrawer: EthAddress.fromString(result.exit.recipientOrWithdrawer),
|
|
1225
|
+
isRecipient: result.exit.isRecipient,
|
|
1226
|
+
exists: result.exit.exists,
|
|
1227
|
+
},
|
|
1228
|
+
config: {
|
|
1229
|
+
publicKey: {
|
|
1230
|
+
x: result.config.publicKey.x,
|
|
1231
|
+
y: result.config.publicKey.y,
|
|
1232
|
+
},
|
|
1233
|
+
withdrawer: EthAddress.fromString(result.config.withdrawer),
|
|
1234
|
+
},
|
|
1235
|
+
};
|
|
698
1236
|
}
|
|
699
1237
|
|
|
700
|
-
getStatus(address: Hex | EthAddress) {
|
|
1238
|
+
async getStatus(address: Hex | EthAddress): Promise<AttesterStatus> {
|
|
701
1239
|
if (address instanceof EthAddress) {
|
|
702
1240
|
address = address.toString();
|
|
703
1241
|
}
|
|
704
|
-
return this.rollup.read.getStatus([address]);
|
|
1242
|
+
return (await this.rollup.read.getStatus([address])) as AttesterStatus;
|
|
705
1243
|
}
|
|
706
1244
|
|
|
707
|
-
getBlobCommitmentsHash(
|
|
708
|
-
return this.rollup.read.getBlobCommitmentsHash([
|
|
1245
|
+
async getBlobCommitmentsHash(checkpointNumber: CheckpointNumber): Promise<Buffer32> {
|
|
1246
|
+
return Buffer32.fromString(await this.rollup.read.getBlobCommitmentsHash([BigInt(checkpointNumber)]));
|
|
709
1247
|
}
|
|
710
1248
|
|
|
711
|
-
getCurrentBlobCommitmentsHash() {
|
|
712
|
-
return this.rollup.read.getCurrentBlobCommitmentsHash();
|
|
1249
|
+
async getCurrentBlobCommitmentsHash(): Promise<Buffer32> {
|
|
1250
|
+
return Buffer32.fromString(await this.rollup.read.getCurrentBlobCommitmentsHash());
|
|
713
1251
|
}
|
|
714
1252
|
|
|
715
|
-
getStakingAsset() {
|
|
716
|
-
return this.rollup.read.getStakingAsset();
|
|
1253
|
+
async getStakingAsset(): Promise<EthAddress> {
|
|
1254
|
+
return EthAddress.fromString(await this.rollup.read.getStakingAsset());
|
|
717
1255
|
}
|
|
718
1256
|
|
|
719
|
-
getRewardConfig() {
|
|
720
|
-
|
|
1257
|
+
async getRewardConfig(): Promise<RewardConfig> {
|
|
1258
|
+
const result = await this.rollup.read.getRewardConfig();
|
|
1259
|
+
return {
|
|
1260
|
+
rewardDistributor: EthAddress.fromString(result.rewardDistributor),
|
|
1261
|
+
sequencerBps: BigInt(result.sequencerBps),
|
|
1262
|
+
booster: EthAddress.fromString(result.booster),
|
|
1263
|
+
checkpointReward: result.checkpointReward,
|
|
1264
|
+
};
|
|
721
1265
|
}
|
|
722
1266
|
|
|
723
1267
|
setupEpoch(l1TxUtils: L1TxUtils) {
|
|
724
1268
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
725
1269
|
to: this.address,
|
|
1270
|
+
abi: RollupAbi,
|
|
726
1271
|
data: encodeFunctionData({
|
|
727
1272
|
abi: RollupAbi,
|
|
728
1273
|
functionName: 'setupEpoch',
|
|
@@ -734,6 +1279,7 @@ export class RollupContract {
|
|
|
734
1279
|
vote(l1TxUtils: L1TxUtils, proposalId: bigint) {
|
|
735
1280
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
736
1281
|
to: this.address,
|
|
1282
|
+
abi: RollupAbi,
|
|
737
1283
|
data: encodeFunctionData({
|
|
738
1284
|
abi: RollupAbi,
|
|
739
1285
|
functionName: 'vote',
|
|
@@ -760,15 +1306,17 @@ export class RollupContract {
|
|
|
760
1306
|
);
|
|
761
1307
|
}
|
|
762
1308
|
|
|
763
|
-
public
|
|
764
|
-
|
|
1309
|
+
public listenToCheckpointInvalidated(
|
|
1310
|
+
callback: (args: { checkpointNumber: CheckpointNumber; event: Log }) => unknown,
|
|
1311
|
+
): WatchContractEventReturnType {
|
|
1312
|
+
return this.rollup.watchEvent.CheckpointInvalidated(
|
|
765
1313
|
{},
|
|
766
1314
|
{
|
|
767
1315
|
onLogs: logs => {
|
|
768
1316
|
for (const log of logs) {
|
|
769
1317
|
const args = log.args;
|
|
770
|
-
if (args.
|
|
771
|
-
callback({
|
|
1318
|
+
if (args.checkpointNumber !== undefined) {
|
|
1319
|
+
callback({ checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber), event: log });
|
|
772
1320
|
}
|
|
773
1321
|
}
|
|
774
1322
|
},
|
|
@@ -800,4 +1348,92 @@ export class RollupContract {
|
|
|
800
1348
|
},
|
|
801
1349
|
);
|
|
802
1350
|
}
|
|
1351
|
+
|
|
1352
|
+
/**
|
|
1353
|
+
* Fetches OwnershipTransferred events emitted on the L1 block this rollup was deployed on.
|
|
1354
|
+
* The Rollup inherits from Ownable and emits this event in its constructor, so the event
|
|
1355
|
+
* is guaranteed to exist on `l1StartBlock` for any correctly deployed rollup. Used as a
|
|
1356
|
+
* probe to detect RPC nodes that prune historical logs.
|
|
1357
|
+
*/
|
|
1358
|
+
async getOwnershipTransferredEventsAtDeploy() {
|
|
1359
|
+
const l1StartBlock = await this.getL1StartBlock();
|
|
1360
|
+
return await this.rollup.getEvents.OwnershipTransferred({}, { fromBlock: l1StartBlock, toBlock: l1StartBlock });
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
/** Fetches CheckpointProposed events within the given block range. */
|
|
1364
|
+
async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
|
|
1365
|
+
const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
|
|
1366
|
+
return logs
|
|
1367
|
+
.filter(log => log.blockNumber! >= fromBlock && log.blockNumber! <= toBlock)
|
|
1368
|
+
.map(log => ({
|
|
1369
|
+
l1BlockNumber: log.blockNumber!,
|
|
1370
|
+
l1BlockHash: Buffer32.fromString(log.blockHash!),
|
|
1371
|
+
l1TransactionHash: log.transactionHash!,
|
|
1372
|
+
args: {
|
|
1373
|
+
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
1374
|
+
archive: Fr.fromString(log.args.archive!),
|
|
1375
|
+
versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
|
|
1376
|
+
attestationsHash: (() => {
|
|
1377
|
+
if (!log.args.attestationsHash) {
|
|
1378
|
+
throw new Error(
|
|
1379
|
+
`CheckpointProposed event missing attestationsHash for checkpoint ${log.args.checkpointNumber}`,
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
return Buffer32.fromString(log.args.attestationsHash);
|
|
1383
|
+
})(),
|
|
1384
|
+
payloadDigest: (() => {
|
|
1385
|
+
if (!log.args.payloadDigest) {
|
|
1386
|
+
throw new Error(
|
|
1387
|
+
`CheckpointProposed event missing payloadDigest for checkpoint ${log.args.checkpointNumber}`,
|
|
1388
|
+
);
|
|
1389
|
+
}
|
|
1390
|
+
return Buffer32.fromString(log.args.payloadDigest);
|
|
1391
|
+
})(),
|
|
1392
|
+
},
|
|
1393
|
+
}));
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
/** Packs pending and proven checkpoint numbers into the chain tips storage format. */
|
|
1397
|
+
static packChainTips(pendingCheckpointNumber: bigint, provenCheckpointNumber: bigint): bigint {
|
|
1398
|
+
return (pendingCheckpointNumber << 128n) | (provenCheckpointNumber & ((1n << 128n) - 1n));
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
/** Storage slot for the chain tips (offset 0 within the STF storage struct). */
|
|
1402
|
+
static get chainTipsStorageSlot(): bigint {
|
|
1403
|
+
return BigInt(RollupContract.stfStorageSlot);
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
/**
|
|
1407
|
+
* Computes the storage slot for a field within a tempCheckpointLog entry.
|
|
1408
|
+
* @param checkpointNumber - The checkpoint number
|
|
1409
|
+
* @param field - The field within the CompressedTempCheckpointLog struct
|
|
1410
|
+
*/
|
|
1411
|
+
async getTempCheckpointLogStorageSlot(
|
|
1412
|
+
checkpointNumber: CheckpointNumber,
|
|
1413
|
+
field: TempCheckpointLogField,
|
|
1414
|
+
): Promise<bigint> {
|
|
1415
|
+
const [epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
1416
|
+
this.getEpochDuration(),
|
|
1417
|
+
this.getProofSubmissionEpochs(),
|
|
1418
|
+
]);
|
|
1419
|
+
return this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, { epochDuration, proofSubmissionEpochs });
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
private computeTempCheckpointLogStorageSlot(
|
|
1423
|
+
checkpointNumber: CheckpointNumber,
|
|
1424
|
+
field: TempCheckpointLogField,
|
|
1425
|
+
constants: { epochDuration: number; proofSubmissionEpochs: number },
|
|
1426
|
+
): bigint {
|
|
1427
|
+
const fieldOffset = BigInt(field);
|
|
1428
|
+
const { epochDuration, proofSubmissionEpochs } = constants;
|
|
1429
|
+
const roundaboutSize = BigInt(epochDuration) * (BigInt(proofSubmissionEpochs) + 1n) + 1n;
|
|
1430
|
+
const tempCheckpointLogsBase = BigInt(RollupContract.stfStorageSlot) + 2n;
|
|
1431
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
1432
|
+
const entryBase = BigInt(
|
|
1433
|
+
keccak256(
|
|
1434
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsBase]),
|
|
1435
|
+
),
|
|
1436
|
+
);
|
|
1437
|
+
return entryBase + fieldOffset;
|
|
1438
|
+
}
|
|
803
1439
|
}
|