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