@aztec/ethereum 0.0.1-commit.5daedc8 → 0.0.1-commit.6201a7b05
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 -3
- package/dest/config.d.ts +26 -73
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +64 -387
- package/dest/contracts/chain_state_override.d.ts +38 -0
- package/dest/contracts/chain_state_override.d.ts.map +1 -0
- package/dest/contracts/chain_state_override.js +100 -0
- package/dest/contracts/empire_base.d.ts +4 -1
- package/dest/contracts/empire_base.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 +101 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
- package/dest/contracts/fee_asset_price_oracle.js +651 -0
- package/dest/contracts/governance.d.ts +3 -1
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +14 -4
- package/dest/contracts/governance_proposer.d.ts +4 -1
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +404 -9
- package/dest/contracts/inbox.d.ts +24 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +41 -1
- 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 +51 -2
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +87 -1
- package/dest/contracts/outbox.d.ts +41 -0
- package/dest/contracts/outbox.d.ts.map +1 -0
- package/dest/contracts/outbox.js +86 -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 +5178 -108
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +1004 -188
- package/dest/contracts/{tally_slashing_proposer.d.ts → slashing_proposer.d.ts} +5 -5
- 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 +256 -0
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
- package/dest/deploy_aztec_l1_contracts.js +411 -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/forwarder_proxy.d.ts +32 -0
- package/dest/forwarder_proxy.d.ts.map +1 -0
- package/dest/forwarder_proxy.js +93 -0
- 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 +14161 -17158
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +9 -24
- package/dest/l1_contract_addresses.d.ts +1 -5
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +3 -9
- package/dest/l1_reader.d.ts +5 -1
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +13 -2
- package/dest/l1_tx_utils/config.d.ts +9 -3
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +31 -4
- 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 +233 -0
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -0
- package/dest/l1_tx_utils/l1_fee_analyzer.js +506 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +20 -7
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +98 -61
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +4 -15
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +61 -164
- package/dest/l1_tx_utils/tx_delayer.d.ts +56 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
- package/dest/{test → l1_tx_utils}/tx_delayer.js +65 -36
- 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 +36 -14
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +45 -11
- package/dest/test/eth_cheat_codes.d.ts +18 -4
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +10 -6
- 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 +13 -6
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +41 -7
- package/dest/test/start_anvil.d.ts +24 -2
- 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/types.d.ts +57 -2
- package/dest/types.d.ts.map +1 -1
- package/dest/utils.d.ts +16 -3
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +80 -12
- package/package.json +33 -16
- package/src/client.ts +28 -2
- package/src/config.ts +82 -468
- package/src/contracts/README.md +157 -0
- package/src/contracts/chain_state_override.ts +147 -0
- package/src/contracts/empire_base.ts +3 -1
- package/src/contracts/fee_asset_handler.ts +10 -7
- package/src/contracts/fee_asset_price_oracle.ts +280 -0
- package/src/contracts/governance.ts +13 -4
- package/src/contracts/governance_proposer.ts +16 -2
- package/src/contracts/inbox.ts +63 -3
- package/src/contracts/index.ts +5 -2
- package/src/contracts/log.ts +13 -0
- package/src/contracts/multicall.ts +70 -3
- package/src/contracts/outbox.ts +98 -0
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +701 -149
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +18 -14
- package/src/deploy_aztec_l1_contracts.ts +646 -0
- package/src/deploy_l1_contract.ts +362 -0
- package/src/forwarder_proxy.ts +108 -0
- package/src/generated/l1-contracts-defaults.ts +32 -0
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +21 -26
- package/src/l1_reader.ts +22 -2
- package/src/l1_tx_utils/config.ts +44 -6
- 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 +803 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +98 -40
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +75 -210
- package/src/{test → l1_tx_utils}/tx_delayer.ts +82 -52
- package/src/publisher_manager.ts +107 -10
- package/src/queries.ts +81 -7
- package/src/test/chain_monitor.ts +82 -18
- package/src/test/eth_cheat_codes.ts +8 -6
- package/src/test/index.ts +0 -2
- package/src/test/rollup_cheat_codes.ts +43 -10
- package/src/test/start_anvil.ts +178 -28
- package/src/test/upgrade_utils.ts +2 -2
- package/src/types.ts +62 -0
- package/src/utils.ts +100 -15
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -66
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -200
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- package/dest/deploy_l1_contracts.d.ts +0 -673
- package/dest/deploy_l1_contracts.d.ts.map +0 -1
- package/dest/deploy_l1_contracts.js +0 -1491
- 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 -265
- package/src/deploy_l1_contracts.ts +0 -1869
- 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,7 +1,12 @@
|
|
|
1
|
-
import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
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';
|
|
8
|
+
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
9
|
+
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
5
10
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
6
11
|
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
7
12
|
|
|
@@ -10,8 +15,10 @@ import {
|
|
|
10
15
|
type Account,
|
|
11
16
|
type GetContractReturnType,
|
|
12
17
|
type Hex,
|
|
18
|
+
type Log,
|
|
13
19
|
type StateOverride,
|
|
14
20
|
type WatchContractEventReturnType,
|
|
21
|
+
encodeAbiParameters,
|
|
15
22
|
encodeFunctionData,
|
|
16
23
|
getContract,
|
|
17
24
|
hexToBigInt,
|
|
@@ -19,16 +26,16 @@ import {
|
|
|
19
26
|
} from 'viem';
|
|
20
27
|
|
|
21
28
|
import { getPublicClient } from '../client.js';
|
|
22
|
-
import type {
|
|
29
|
+
import type { DeployAztecL1ContractsReturnType } from '../deploy_aztec_l1_contracts.js';
|
|
23
30
|
import type { L1ContractAddresses } from '../l1_contract_addresses.js';
|
|
24
31
|
import type { L1ReaderConfig } from '../l1_reader.js';
|
|
25
32
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
26
33
|
import type { ViemClient } from '../types.js';
|
|
27
34
|
import { formatViemError } from '../utils.js';
|
|
28
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
29
35
|
import { GSEContract } from './gse.js';
|
|
36
|
+
import type { L1EventLog } from './log.js';
|
|
30
37
|
import { SlasherContract } from './slasher_contract.js';
|
|
31
|
-
import {
|
|
38
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
32
39
|
import { checkBlockTag } from './utils.js';
|
|
33
40
|
|
|
34
41
|
export type ViemCommitteeAttestation = {
|
|
@@ -50,20 +57,22 @@ export type L1RollupContractAddresses = Pick<
|
|
|
50
57
|
| 'feeJuiceAddress'
|
|
51
58
|
| 'stakingAssetAddress'
|
|
52
59
|
| 'rewardDistributorAddress'
|
|
53
|
-
| 'slashFactoryAddress'
|
|
54
60
|
| 'gseAddress'
|
|
55
61
|
>;
|
|
56
62
|
|
|
57
63
|
export type EpochProofPublicInputArgs = {
|
|
58
64
|
previousArchive: `0x${string}`;
|
|
59
65
|
endArchive: `0x${string}`;
|
|
66
|
+
outHash: `0x${string}`;
|
|
60
67
|
proverId: `0x${string}`;
|
|
61
68
|
};
|
|
62
69
|
|
|
63
70
|
export type ViemHeader = {
|
|
64
71
|
lastArchiveRoot: `0x${string}`;
|
|
65
72
|
blockHeadersHash: `0x${string}`;
|
|
66
|
-
|
|
73
|
+
blobsHash: `0x${string}`;
|
|
74
|
+
inHash: `0x${string}`;
|
|
75
|
+
outHash: `0x${string}`;
|
|
67
76
|
slotNumber: bigint;
|
|
68
77
|
timestamp: bigint;
|
|
69
78
|
coinbase: `0x${string}`;
|
|
@@ -72,27 +81,150 @@ export type ViemHeader = {
|
|
|
72
81
|
totalManaUsed: bigint;
|
|
73
82
|
};
|
|
74
83
|
|
|
75
|
-
export type ViemContentCommitment = {
|
|
76
|
-
blobsHash: `0x${string}`;
|
|
77
|
-
inHash: `0x${string}`;
|
|
78
|
-
outHash: `0x${string}`;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
84
|
export type ViemGasFees = {
|
|
82
85
|
feePerDaGas: bigint;
|
|
83
86
|
feePerL2Gas: bigint;
|
|
84
87
|
};
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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,
|
|
98
|
+
}
|
|
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,
|
|
90
141
|
}
|
|
91
142
|
|
|
143
|
+
/** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
|
|
144
|
+
export type ManaMinFeeComponents = {
|
|
145
|
+
sequencerCost: bigint;
|
|
146
|
+
proverCost: bigint;
|
|
147
|
+
congestionCost: bigint;
|
|
148
|
+
congestionMultiplier: bigint;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Reward configuration for the rollup
|
|
153
|
+
*/
|
|
154
|
+
export type RewardConfig = {
|
|
155
|
+
rewardDistributor: EthAddress;
|
|
156
|
+
sequencerBps: bigint;
|
|
157
|
+
booster: EthAddress;
|
|
158
|
+
checkpointReward: bigint;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Exit information for a validator
|
|
163
|
+
*/
|
|
164
|
+
export type Exit = {
|
|
165
|
+
withdrawalId: bigint;
|
|
166
|
+
amount: bigint;
|
|
167
|
+
exitableAt: bigint;
|
|
168
|
+
recipientOrWithdrawer: EthAddress;
|
|
169
|
+
isRecipient: boolean;
|
|
170
|
+
exists: boolean;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Attester configuration including public key and withdrawer
|
|
175
|
+
*/
|
|
176
|
+
export type AttesterConfig = {
|
|
177
|
+
publicKey: {
|
|
178
|
+
x: bigint;
|
|
179
|
+
y: bigint;
|
|
180
|
+
};
|
|
181
|
+
withdrawer: EthAddress;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Complete view of an attester's state
|
|
186
|
+
*/
|
|
187
|
+
export type AttesterView = {
|
|
188
|
+
status: AttesterStatus;
|
|
189
|
+
effectiveBalance: bigint;
|
|
190
|
+
exit: Exit;
|
|
191
|
+
config: AttesterConfig;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Return for a status call
|
|
196
|
+
*/
|
|
197
|
+
export type RollupStatusResponse = {
|
|
198
|
+
provenCheckpointNumber: CheckpointNumber;
|
|
199
|
+
provenArchive: Fr;
|
|
200
|
+
pendingCheckpointNumber: CheckpointNumber;
|
|
201
|
+
pendingArchive: Fr;
|
|
202
|
+
archiveOfMyCheckpoint: Fr;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/** Arguments for the CheckpointProposed event. */
|
|
206
|
+
export type CheckpointProposedArgs = {
|
|
207
|
+
checkpointNumber: CheckpointNumber;
|
|
208
|
+
archive: Fr;
|
|
209
|
+
versionedBlobHashes: Buffer[];
|
|
210
|
+
/** Hash of attestations emitted in the CheckpointProposed event. */
|
|
211
|
+
attestationsHash: Buffer32;
|
|
212
|
+
/** Digest of the payload emitted in the CheckpointProposed event. */
|
|
213
|
+
payloadDigest: Buffer32;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/** Log type for CheckpointProposed events. */
|
|
217
|
+
export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
218
|
+
|
|
92
219
|
export class RollupContract {
|
|
93
220
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
221
|
+
private readonly logger = createLogger('ethereum:rollup');
|
|
94
222
|
|
|
95
223
|
private static cachedStfStorageSlot: Hex | undefined;
|
|
224
|
+
private cachedEscapeHatch?: {
|
|
225
|
+
address: EthAddress;
|
|
226
|
+
contract: GetContractReturnType<typeof EscapeHatchAbi, ViemClient>;
|
|
227
|
+
};
|
|
96
228
|
|
|
97
229
|
static get checkBlobStorageSlot(): bigint {
|
|
98
230
|
const asString = RollupStorage.find(storage => storage.label === 'checkBlob')?.slot;
|
|
@@ -106,7 +238,7 @@ export class RollupContract {
|
|
|
106
238
|
return (RollupContract.cachedStfStorageSlot ??= keccak256(Buffer.from('aztec.stf.storage', 'utf-8')));
|
|
107
239
|
}
|
|
108
240
|
|
|
109
|
-
static getFromL1ContractsValues(deployL1ContractsValues:
|
|
241
|
+
static getFromL1ContractsValues(deployL1ContractsValues: DeployAztecL1ContractsReturnType) {
|
|
110
242
|
const {
|
|
111
243
|
l1Client,
|
|
112
244
|
l1ContractAddresses: { rollupAddress },
|
|
@@ -130,8 +262,8 @@ export class RollupContract {
|
|
|
130
262
|
this.rollup = getContract({ address, abi: RollupAbi, client });
|
|
131
263
|
}
|
|
132
264
|
|
|
133
|
-
getGSE() {
|
|
134
|
-
return this.rollup.read.getGSE();
|
|
265
|
+
async getGSE(): Promise<EthAddress> {
|
|
266
|
+
return EthAddress.fromString(await this.rollup.read.getGSE());
|
|
135
267
|
}
|
|
136
268
|
|
|
137
269
|
public get address() {
|
|
@@ -142,54 +274,38 @@ export class RollupContract {
|
|
|
142
274
|
return this.rollup;
|
|
143
275
|
}
|
|
144
276
|
|
|
145
|
-
public async getSlashingProposer(): Promise<
|
|
146
|
-
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
147
|
-
> {
|
|
277
|
+
public async getSlashingProposer(): Promise<SlashingProposerContract | undefined> {
|
|
148
278
|
const slasher = await this.getSlasherContract();
|
|
149
279
|
if (!slasher) {
|
|
150
280
|
return undefined;
|
|
151
281
|
}
|
|
152
282
|
|
|
153
283
|
const proposerAddress = await slasher.getProposer();
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
type: 'function',
|
|
157
|
-
name: 'SLASHING_PROPOSER_TYPE',
|
|
158
|
-
inputs: [],
|
|
159
|
-
outputs: [{ name: '', type: 'uint8', internalType: 'enum SlasherFlavor' }],
|
|
160
|
-
stateMutability: 'view',
|
|
161
|
-
},
|
|
162
|
-
] as const;
|
|
163
|
-
|
|
164
|
-
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
|
|
165
|
-
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
166
|
-
if (proposerType === SlashingProposerType.Tally.valueOf()) {
|
|
167
|
-
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
168
|
-
} else if (proposerType === SlashingProposerType.Empire.valueOf()) {
|
|
169
|
-
return new EmpireSlashingProposerContract(this.client, proposerAddress);
|
|
170
|
-
} else {
|
|
171
|
-
throw new Error(`Unknown slashing proposer type: ${proposerType}`);
|
|
284
|
+
if (proposerAddress.isZero()) {
|
|
285
|
+
return undefined;
|
|
172
286
|
}
|
|
287
|
+
|
|
288
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
173
289
|
}
|
|
174
290
|
|
|
175
291
|
@memoize
|
|
176
|
-
getL1StartBlock() {
|
|
292
|
+
getL1StartBlock(): Promise<bigint> {
|
|
177
293
|
return this.rollup.read.L1_BLOCK_AT_GENESIS();
|
|
178
294
|
}
|
|
179
295
|
|
|
180
296
|
@memoize
|
|
181
|
-
getL1GenesisTime() {
|
|
297
|
+
getL1GenesisTime(): Promise<bigint> {
|
|
182
298
|
return this.rollup.read.getGenesisTime();
|
|
183
299
|
}
|
|
184
300
|
|
|
185
301
|
@memoize
|
|
186
|
-
getProofSubmissionEpochs() {
|
|
187
|
-
return this.rollup.read.getProofSubmissionEpochs();
|
|
302
|
+
async getProofSubmissionEpochs(): Promise<number> {
|
|
303
|
+
return Number(await this.rollup.read.getProofSubmissionEpochs());
|
|
188
304
|
}
|
|
189
305
|
|
|
190
306
|
@memoize
|
|
191
|
-
getEpochDuration() {
|
|
192
|
-
return this.rollup.read.getEpochDuration();
|
|
307
|
+
async getEpochDuration(): Promise<number> {
|
|
308
|
+
return Number(await this.rollup.read.getEpochDuration());
|
|
193
309
|
}
|
|
194
310
|
|
|
195
311
|
@memoize
|
|
@@ -198,68 +314,82 @@ export class RollupContract {
|
|
|
198
314
|
}
|
|
199
315
|
|
|
200
316
|
@memoize
|
|
201
|
-
getTargetCommitteeSize() {
|
|
202
|
-
return this.rollup.read.getTargetCommitteeSize();
|
|
317
|
+
async getTargetCommitteeSize(): Promise<number> {
|
|
318
|
+
return Number(await this.rollup.read.getTargetCommitteeSize());
|
|
203
319
|
}
|
|
204
320
|
|
|
205
321
|
@memoize
|
|
206
|
-
getEjectionThreshold() {
|
|
322
|
+
getEjectionThreshold(): Promise<bigint> {
|
|
207
323
|
return this.rollup.read.getEjectionThreshold();
|
|
208
324
|
}
|
|
209
325
|
|
|
210
326
|
@memoize
|
|
211
|
-
getLocalEjectionThreshold() {
|
|
327
|
+
getLocalEjectionThreshold(): Promise<bigint> {
|
|
212
328
|
return this.rollup.read.getLocalEjectionThreshold();
|
|
213
329
|
}
|
|
214
330
|
|
|
215
331
|
@memoize
|
|
216
|
-
getLagInEpochsForValidatorSet() {
|
|
217
|
-
return this.rollup.read.getLagInEpochsForValidatorSet();
|
|
332
|
+
async getLagInEpochsForValidatorSet(): Promise<number> {
|
|
333
|
+
return Number(await this.rollup.read.getLagInEpochsForValidatorSet());
|
|
218
334
|
}
|
|
219
335
|
|
|
220
336
|
@memoize
|
|
221
|
-
getLagInEpochsForRandao() {
|
|
222
|
-
return this.rollup.read.getLagInEpochsForRandao();
|
|
337
|
+
async getLagInEpochsForRandao(): Promise<number> {
|
|
338
|
+
return Number(await this.rollup.read.getLagInEpochsForRandao());
|
|
223
339
|
}
|
|
224
340
|
|
|
225
341
|
@memoize
|
|
226
|
-
getActivationThreshold() {
|
|
342
|
+
getActivationThreshold(): Promise<bigint> {
|
|
227
343
|
return this.rollup.read.getActivationThreshold();
|
|
228
344
|
}
|
|
229
345
|
|
|
230
346
|
@memoize
|
|
231
|
-
getExitDelay() {
|
|
232
|
-
return this.rollup.read.getExitDelay();
|
|
347
|
+
async getExitDelay(): Promise<number> {
|
|
348
|
+
return Number(await this.rollup.read.getExitDelay());
|
|
233
349
|
}
|
|
234
350
|
|
|
235
351
|
@memoize
|
|
236
|
-
getManaTarget() {
|
|
352
|
+
getManaTarget(): Promise<bigint> {
|
|
237
353
|
return this.rollup.read.getManaTarget();
|
|
238
354
|
}
|
|
239
355
|
|
|
240
356
|
@memoize
|
|
241
|
-
getProvingCostPerMana() {
|
|
357
|
+
getProvingCostPerMana(): Promise<bigint> {
|
|
242
358
|
return this.rollup.read.getProvingCostPerManaInEth();
|
|
243
359
|
}
|
|
244
360
|
|
|
245
361
|
@memoize
|
|
246
|
-
getProvingCostPerManaInFeeAsset() {
|
|
362
|
+
getProvingCostPerManaInFeeAsset(): Promise<bigint> {
|
|
247
363
|
return this.rollup.read.getProvingCostPerManaInFeeAsset();
|
|
248
364
|
}
|
|
249
365
|
|
|
250
366
|
@memoize
|
|
251
|
-
getManaLimit() {
|
|
367
|
+
getManaLimit(): Promise<bigint> {
|
|
252
368
|
return this.rollup.read.getManaLimit();
|
|
253
369
|
}
|
|
254
370
|
|
|
255
371
|
@memoize
|
|
256
|
-
getVersion() {
|
|
372
|
+
getVersion(): Promise<bigint> {
|
|
257
373
|
return this.rollup.read.getVersion();
|
|
258
374
|
}
|
|
259
375
|
|
|
260
376
|
@memoize
|
|
261
|
-
async getGenesisArchiveTreeRoot(): Promise
|
|
262
|
-
return await this.rollup.read.archiveAt([0n]);
|
|
377
|
+
async getGenesisArchiveTreeRoot(): Promise<Fr> {
|
|
378
|
+
return Fr.fromString(await this.rollup.read.archiveAt([0n]));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
@memoize
|
|
382
|
+
async getVkTreeRoot(): Promise<Fr> {
|
|
383
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 3n;
|
|
384
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
385
|
+
return Fr.fromString(value ?? '0x0');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
@memoize
|
|
389
|
+
async getProtocolContractsHash(): Promise<Fr> {
|
|
390
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 4n;
|
|
391
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
392
|
+
return Fr.fromString(value ?? '0x0');
|
|
263
393
|
}
|
|
264
394
|
|
|
265
395
|
/**
|
|
@@ -274,13 +404,25 @@ export class RollupContract {
|
|
|
274
404
|
slotDuration: number;
|
|
275
405
|
epochDuration: number;
|
|
276
406
|
proofSubmissionEpochs: number;
|
|
407
|
+
targetCommitteeSize: number;
|
|
408
|
+
rollupManaLimit: number;
|
|
277
409
|
}> {
|
|
278
|
-
const [
|
|
410
|
+
const [
|
|
411
|
+
l1StartBlock,
|
|
412
|
+
l1GenesisTime,
|
|
413
|
+
slotDuration,
|
|
414
|
+
epochDuration,
|
|
415
|
+
proofSubmissionEpochs,
|
|
416
|
+
targetCommitteeSize,
|
|
417
|
+
rollupManaLimit,
|
|
418
|
+
] = await Promise.all([
|
|
279
419
|
this.getL1StartBlock(),
|
|
280
420
|
this.getL1GenesisTime(),
|
|
281
421
|
this.getSlotDuration(),
|
|
282
422
|
this.getEpochDuration(),
|
|
283
423
|
this.getProofSubmissionEpochs(),
|
|
424
|
+
this.getTargetCommitteeSize(),
|
|
425
|
+
this.getManaLimit(),
|
|
284
426
|
]);
|
|
285
427
|
return {
|
|
286
428
|
l1StartBlock,
|
|
@@ -288,30 +430,88 @@ export class RollupContract {
|
|
|
288
430
|
slotDuration,
|
|
289
431
|
epochDuration: Number(epochDuration),
|
|
290
432
|
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
433
|
+
targetCommitteeSize,
|
|
434
|
+
rollupManaLimit: Number(rollupManaLimit),
|
|
291
435
|
};
|
|
292
436
|
}
|
|
293
437
|
|
|
294
|
-
getSlasherAddress() {
|
|
295
|
-
return this.rollup.read.getSlasher();
|
|
438
|
+
async getSlasherAddress(): Promise<EthAddress> {
|
|
439
|
+
return EthAddress.fromString(await this.rollup.read.getSlasher());
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Returns the configured escape hatch contract address, or zero if disabled.
|
|
444
|
+
*/
|
|
445
|
+
async getEscapeHatchAddress(): Promise<EthAddress> {
|
|
446
|
+
return EthAddress.fromString(await this.rollup.read.getEscapeHatch());
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
private async getEscapeHatchContract(): Promise<
|
|
450
|
+
GetContractReturnType<typeof EscapeHatchAbi, ViemClient> | undefined
|
|
451
|
+
> {
|
|
452
|
+
const escapeHatchAddress = await this.getEscapeHatchAddress();
|
|
453
|
+
if (escapeHatchAddress.isZero()) {
|
|
454
|
+
return undefined;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Cache the viem contract wrapper since it will be used frequently.
|
|
458
|
+
if (!this.cachedEscapeHatch || !this.cachedEscapeHatch.address.equals(escapeHatchAddress)) {
|
|
459
|
+
this.cachedEscapeHatch = {
|
|
460
|
+
address: escapeHatchAddress,
|
|
461
|
+
contract: getContract({
|
|
462
|
+
address: escapeHatchAddress.toString(),
|
|
463
|
+
abi: EscapeHatchAbi,
|
|
464
|
+
client: this.client,
|
|
465
|
+
}),
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return this.cachedEscapeHatch.contract;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Returns whether the escape hatch is open for the given epoch.
|
|
474
|
+
* If escape hatch is not configured, returns false.
|
|
475
|
+
*
|
|
476
|
+
* This function is intentionally defensive: any failure to query the escape hatch
|
|
477
|
+
* (RPC issues, transient errors, etc.) is treated as "closed" to avoid callers
|
|
478
|
+
* needing to sprinkle try/catch everywhere.
|
|
479
|
+
*/
|
|
480
|
+
async isEscapeHatchOpen(epoch: EpochNumber): Promise<boolean> {
|
|
481
|
+
try {
|
|
482
|
+
const escapeHatch = await this.getEscapeHatchContract();
|
|
483
|
+
if (!escapeHatch) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
|
|
488
|
+
return isOpen;
|
|
489
|
+
} catch (err) {
|
|
490
|
+
this.logger.warn('isEscapeHatchOpen failed (treating as closed); RPC or contract error may cause liveness risk', {
|
|
491
|
+
epoch: Number(epoch),
|
|
492
|
+
error: err,
|
|
493
|
+
});
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
296
496
|
}
|
|
297
497
|
|
|
298
498
|
/**
|
|
299
499
|
* Returns a SlasherContract instance for interacting with the slasher contract.
|
|
300
500
|
*/
|
|
301
501
|
async getSlasherContract(): Promise<SlasherContract | undefined> {
|
|
302
|
-
const slasherAddress =
|
|
502
|
+
const slasherAddress = await this.getSlasherAddress();
|
|
303
503
|
if (slasherAddress.isZero()) {
|
|
304
504
|
return undefined;
|
|
305
505
|
}
|
|
306
506
|
return new SlasherContract(this.client, slasherAddress);
|
|
307
507
|
}
|
|
308
508
|
|
|
309
|
-
getOwner() {
|
|
310
|
-
return this.rollup.read.owner();
|
|
509
|
+
async getOwner(): Promise<EthAddress> {
|
|
510
|
+
return EthAddress.fromString(await this.rollup.read.owner());
|
|
311
511
|
}
|
|
312
512
|
|
|
313
|
-
getActiveAttesterCount() {
|
|
314
|
-
return this.rollup.read.getActiveAttesterCount();
|
|
513
|
+
async getActiveAttesterCount(): Promise<number> {
|
|
514
|
+
return Number(await this.rollup.read.getActiveAttesterCount());
|
|
315
515
|
}
|
|
316
516
|
|
|
317
517
|
public async getSlashingProposerAddress() {
|
|
@@ -322,31 +522,50 @@ export class RollupContract {
|
|
|
322
522
|
return await slasher.getProposer();
|
|
323
523
|
}
|
|
324
524
|
|
|
325
|
-
getCheckpointReward() {
|
|
525
|
+
getCheckpointReward(): Promise<bigint> {
|
|
326
526
|
return this.rollup.read.getCheckpointReward();
|
|
327
527
|
}
|
|
328
528
|
|
|
329
|
-
getCheckpointNumber() {
|
|
330
|
-
|
|
529
|
+
async getCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
530
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
531
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber(options));
|
|
331
532
|
}
|
|
332
533
|
|
|
333
|
-
getProvenCheckpointNumber() {
|
|
334
|
-
|
|
534
|
+
async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
535
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
536
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
335
537
|
}
|
|
336
538
|
|
|
337
|
-
async getSlotNumber(): Promise<SlotNumber> {
|
|
338
|
-
|
|
539
|
+
async getSlotNumber(options?: { blockNumber?: bigint }): Promise<SlotNumber> {
|
|
540
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
541
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot(options));
|
|
339
542
|
}
|
|
340
543
|
|
|
341
|
-
getL1FeesAt(timestamp: bigint) {
|
|
342
|
-
|
|
544
|
+
async getL1FeesAt(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<L1FeeData> {
|
|
545
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
546
|
+
const result = await this.rollup.read.getL1FeesAt([timestamp], options);
|
|
547
|
+
return {
|
|
548
|
+
baseFee: result.baseFee,
|
|
549
|
+
blobFee: result.blobFee,
|
|
550
|
+
};
|
|
343
551
|
}
|
|
344
552
|
|
|
345
|
-
|
|
346
|
-
|
|
553
|
+
async getFeeHeader(checkpointNumber: bigint): Promise<FeeHeader> {
|
|
554
|
+
const result = await this.rollup.read.getFeeHeader([checkpointNumber]);
|
|
555
|
+
return {
|
|
556
|
+
excessMana: result.excessMana,
|
|
557
|
+
manaUsed: result.manaUsed,
|
|
558
|
+
ethPerFeeAsset: result.ethPerFeeAsset,
|
|
559
|
+
congestionCost: result.congestionCost,
|
|
560
|
+
proverCost: result.proverCost,
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
getEthPerFeeAsset(): Promise<bigint> {
|
|
565
|
+
return this.rollup.read.getEthPerFeeAsset();
|
|
347
566
|
}
|
|
348
567
|
|
|
349
|
-
async getCommitteeAt(timestamp: bigint): Promise<
|
|
568
|
+
async getCommitteeAt(timestamp: bigint): Promise<EthAddress[] | undefined> {
|
|
350
569
|
const { result } = await this.client
|
|
351
570
|
.simulateContract({
|
|
352
571
|
address: this.address,
|
|
@@ -361,22 +580,22 @@ export class RollupContract {
|
|
|
361
580
|
throw e;
|
|
362
581
|
});
|
|
363
582
|
|
|
364
|
-
return result;
|
|
583
|
+
return result ? result.map(addr => EthAddress.fromString(addr)) : undefined;
|
|
365
584
|
}
|
|
366
585
|
|
|
367
|
-
getSampleSeedAt(timestamp: bigint) {
|
|
368
|
-
return this.rollup.read.getSampleSeedAt([timestamp]);
|
|
586
|
+
async getSampleSeedAt(timestamp: bigint): Promise<Buffer32> {
|
|
587
|
+
return Buffer32.fromBigInt(await this.rollup.read.getSampleSeedAt([timestamp]));
|
|
369
588
|
}
|
|
370
589
|
|
|
371
|
-
getCurrentSampleSeed() {
|
|
372
|
-
return this.rollup.read.getCurrentSampleSeed();
|
|
590
|
+
async getCurrentSampleSeed(): Promise<Buffer32> {
|
|
591
|
+
return Buffer32.fromBigInt(await this.rollup.read.getCurrentSampleSeed());
|
|
373
592
|
}
|
|
374
593
|
|
|
375
594
|
async getCurrentEpoch(): Promise<EpochNumber> {
|
|
376
595
|
return EpochNumber.fromBigInt(await this.rollup.read.getCurrentEpoch());
|
|
377
596
|
}
|
|
378
597
|
|
|
379
|
-
async getCurrentEpochCommittee(): Promise<
|
|
598
|
+
async getCurrentEpochCommittee(): Promise<EthAddress[] | undefined> {
|
|
380
599
|
const { result } = await this.client
|
|
381
600
|
.simulateContract({
|
|
382
601
|
address: this.address,
|
|
@@ -391,10 +610,10 @@ export class RollupContract {
|
|
|
391
610
|
throw e;
|
|
392
611
|
});
|
|
393
612
|
|
|
394
|
-
return result;
|
|
613
|
+
return result ? result.map(addr => EthAddress.fromString(addr)) : undefined;
|
|
395
614
|
}
|
|
396
615
|
|
|
397
|
-
async getCurrentProposer() {
|
|
616
|
+
async getCurrentProposer(): Promise<EthAddress> {
|
|
398
617
|
const { result } = await this.client.simulateContract({
|
|
399
618
|
address: this.address,
|
|
400
619
|
abi: RollupAbi,
|
|
@@ -402,10 +621,10 @@ export class RollupContract {
|
|
|
402
621
|
args: [],
|
|
403
622
|
});
|
|
404
623
|
|
|
405
|
-
return result;
|
|
624
|
+
return EthAddress.fromString(result);
|
|
406
625
|
}
|
|
407
626
|
|
|
408
|
-
async getProposerAt(timestamp: bigint) {
|
|
627
|
+
async getProposerAt(timestamp: bigint): Promise<EthAddress> {
|
|
409
628
|
const { result } = await this.client.simulateContract({
|
|
410
629
|
address: this.address,
|
|
411
630
|
abi: RollupAbi,
|
|
@@ -413,27 +632,86 @@ export class RollupContract {
|
|
|
413
632
|
args: [timestamp],
|
|
414
633
|
});
|
|
415
634
|
|
|
416
|
-
return result;
|
|
635
|
+
return EthAddress.fromString(result);
|
|
417
636
|
}
|
|
418
637
|
|
|
419
|
-
getCheckpoint(checkpointNumber: bigint
|
|
420
|
-
|
|
638
|
+
async getCheckpoint(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise<CheckpointLog> {
|
|
639
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
640
|
+
const result = await this.rollup.read.getCheckpoint([BigInt(checkpointNumber)], options);
|
|
641
|
+
return {
|
|
642
|
+
archive: Fr.fromString(result.archive),
|
|
643
|
+
headerHash: Buffer32.fromString(result.headerHash),
|
|
644
|
+
blobCommitmentsHash: Buffer32.fromString(result.blobCommitmentsHash),
|
|
645
|
+
attestationsHash: Buffer32.fromString(result.attestationsHash),
|
|
646
|
+
payloadDigest: Buffer32.fromString(result.payloadDigest),
|
|
647
|
+
slotNumber: SlotNumber.fromBigInt(result.slotNumber),
|
|
648
|
+
feeHeader: {
|
|
649
|
+
excessMana: result.feeHeader.excessMana,
|
|
650
|
+
manaUsed: result.feeHeader.manaUsed,
|
|
651
|
+
ethPerFeeAsset: result.feeHeader.ethPerFeeAsset,
|
|
652
|
+
congestionCost: result.feeHeader.congestionCost,
|
|
653
|
+
proverCost: result.feeHeader.proverCost,
|
|
654
|
+
},
|
|
655
|
+
};
|
|
421
656
|
}
|
|
422
657
|
|
|
423
|
-
|
|
424
|
-
|
|
658
|
+
/** Returns the pending checkpoint from the rollup contract */
|
|
659
|
+
getPendingCheckpoint() {
|
|
660
|
+
// We retry because of race conditions during prunes: we may get a pending checkpoint number which is immediately
|
|
661
|
+
// reorged out due to a prune happening, causing the subsequent getCheckpoint call to fail. So we try again in that case.
|
|
662
|
+
return retry(
|
|
663
|
+
async () => {
|
|
664
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber();
|
|
665
|
+
const pendingCheckpoint = await this.getCheckpoint(pendingCheckpointNumber);
|
|
666
|
+
return pendingCheckpoint;
|
|
667
|
+
},
|
|
668
|
+
'getting pending checkpoint',
|
|
669
|
+
makeBackoff([0.5, 0.5, 0.5]),
|
|
670
|
+
);
|
|
425
671
|
}
|
|
426
672
|
|
|
427
|
-
|
|
673
|
+
/**
|
|
674
|
+
* Returns the effective pending checkpoint, accounting for potential prunes.
|
|
675
|
+
* When a prune can happen, the L1 contract uses the proven checkpoint instead of the pending one.
|
|
676
|
+
* This mirrors the behavior of getEffectivePendingCheckpointNumber in STFLib.sol.
|
|
677
|
+
* @param atTimestamp - The timestamp to evaluate pruneability at. Defaults to the current L1 block timestamp.
|
|
678
|
+
* @param options - Optional L1 block number to pin the queries to.
|
|
679
|
+
*/
|
|
680
|
+
getEffectivePendingCheckpoint(atTimestamp?: bigint, options?: { blockNumber?: bigint }) {
|
|
681
|
+
return retry(
|
|
682
|
+
async () => {
|
|
683
|
+
const timestamp = atTimestamp ?? (await this.client.getBlock()).timestamp;
|
|
684
|
+
const canPrune = await this.canPruneAtTime(timestamp, options);
|
|
685
|
+
if (canPrune) {
|
|
686
|
+
const provenCheckpointNumber = await this.getProvenCheckpointNumber(options);
|
|
687
|
+
return await this.getCheckpoint(provenCheckpointNumber, options);
|
|
688
|
+
}
|
|
689
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber(options);
|
|
690
|
+
return await this.getCheckpoint(pendingCheckpointNumber, options);
|
|
691
|
+
},
|
|
692
|
+
'getting effective pending checkpoint',
|
|
693
|
+
makeBackoff([0.5, 0.5, 0.5]),
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
async getTips(): Promise<{ pending: CheckpointNumber; proven: CheckpointNumber }> {
|
|
698
|
+
const { pending, proven } = await this.rollup.read.getTips();
|
|
699
|
+
return {
|
|
700
|
+
pending: CheckpointNumber.fromBigInt(pending),
|
|
701
|
+
proven: CheckpointNumber.fromBigInt(proven),
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
getTimestampForSlot(slot: SlotNumber): Promise<bigint> {
|
|
428
706
|
return this.rollup.read.getTimestampForSlot([BigInt(slot)]);
|
|
429
707
|
}
|
|
430
708
|
|
|
431
|
-
getEntryQueueLength() {
|
|
432
|
-
return this.rollup.read.getEntryQueueLength();
|
|
709
|
+
async getEntryQueueLength(): Promise<number> {
|
|
710
|
+
return Number(await this.rollup.read.getEntryQueueLength());
|
|
433
711
|
}
|
|
434
712
|
|
|
435
|
-
getAvailableValidatorFlushes() {
|
|
436
|
-
return this.rollup.read.getAvailableValidatorFlushes();
|
|
713
|
+
async getAvailableValidatorFlushes(): Promise<number> {
|
|
714
|
+
return Number(await this.rollup.read.getAvailableValidatorFlushes());
|
|
437
715
|
}
|
|
438
716
|
|
|
439
717
|
async getNextFlushableEpoch(): Promise<EpochNumber> {
|
|
@@ -444,7 +722,7 @@ export class RollupContract {
|
|
|
444
722
|
return EpochNumber.fromBigInt(await this.rollup.read.getCurrentEpoch());
|
|
445
723
|
}
|
|
446
724
|
|
|
447
|
-
async getEpochNumberForCheckpoint(checkpointNumber:
|
|
725
|
+
async getEpochNumberForCheckpoint(checkpointNumber: CheckpointNumber): Promise<EpochNumber> {
|
|
448
726
|
return EpochNumber.fromBigInt(await this.rollup.read.getEpochForCheckpoint([BigInt(checkpointNumber)]));
|
|
449
727
|
}
|
|
450
728
|
|
|
@@ -489,10 +767,11 @@ export class RollupContract {
|
|
|
489
767
|
return EpochNumber.fromBigInt(await this.rollup.read.getEpochAtSlot([BigInt(slotNumber)]));
|
|
490
768
|
}
|
|
491
769
|
|
|
492
|
-
getEpochProofPublicInputs(
|
|
770
|
+
async getEpochProofPublicInputs(
|
|
493
771
|
args: readonly [bigint, bigint, EpochProofPublicInputArgs, readonly `0x${string}`[], `0x${string}`],
|
|
494
|
-
) {
|
|
495
|
-
|
|
772
|
+
): Promise<Fr[]> {
|
|
773
|
+
const result = await this.rollup.read.getEpochProofPublicInputs(args);
|
|
774
|
+
return result.map(Fr.fromString);
|
|
496
775
|
}
|
|
497
776
|
|
|
498
777
|
public async validateHeader(
|
|
@@ -533,14 +812,13 @@ export class RollupContract {
|
|
|
533
812
|
* timestamp of the next L1 block
|
|
534
813
|
* @throws otherwise
|
|
535
814
|
*/
|
|
536
|
-
public async
|
|
815
|
+
public async canProposeAt(
|
|
537
816
|
archive: Buffer,
|
|
538
817
|
account: `0x${string}` | Account,
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
): Promise<{ slot: SlotNumber; checkpointNumber:
|
|
542
|
-
const
|
|
543
|
-
const timeOfNextL1Slot = latestBlock.timestamp + BigInt(slotDuration);
|
|
818
|
+
timestamp: bigint,
|
|
819
|
+
stateOverride: StateOverride = [],
|
|
820
|
+
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
821
|
+
const timeOfNextL1Slot = timestamp;
|
|
544
822
|
const who = typeof account === 'string' ? account : account.address;
|
|
545
823
|
|
|
546
824
|
try {
|
|
@@ -552,10 +830,14 @@ export class RollupContract {
|
|
|
552
830
|
functionName: 'canProposeAtTime',
|
|
553
831
|
args: [timeOfNextL1Slot, `0x${archive.toString('hex')}`, who],
|
|
554
832
|
account,
|
|
555
|
-
stateOverride
|
|
833
|
+
stateOverride,
|
|
556
834
|
});
|
|
557
835
|
|
|
558
|
-
return {
|
|
836
|
+
return {
|
|
837
|
+
slot: SlotNumber.fromBigInt(slot),
|
|
838
|
+
checkpointNumber: CheckpointNumber.fromBigInt(checkpointNumber),
|
|
839
|
+
timeOfNextL1Slot,
|
|
840
|
+
};
|
|
559
841
|
} catch (err: unknown) {
|
|
560
842
|
throw formatViemError(err);
|
|
561
843
|
}
|
|
@@ -567,7 +849,7 @@ export class RollupContract {
|
|
|
567
849
|
* stored in the same slot. If the argument is undefined, it returns an empty override.
|
|
568
850
|
*/
|
|
569
851
|
public async makePendingCheckpointNumberOverride(
|
|
570
|
-
forcePendingCheckpointNumber:
|
|
852
|
+
forcePendingCheckpointNumber: CheckpointNumber | undefined,
|
|
571
853
|
): Promise<StateOverride> {
|
|
572
854
|
if (forcePendingCheckpointNumber === undefined) {
|
|
573
855
|
return [];
|
|
@@ -584,15 +866,161 @@ export class RollupContract {
|
|
|
584
866
|
];
|
|
585
867
|
}
|
|
586
868
|
|
|
869
|
+
/**
|
|
870
|
+
* Returns a state override that sets tempCheckpointLogs[checkpointNumber].feeHeader to the compressed fee header.
|
|
871
|
+
* Used when simulating a propose call where the parent checkpoint hasn't landed on L1 yet (pipelining).
|
|
872
|
+
*/
|
|
873
|
+
public async makeFeeHeaderOverride(checkpointNumber: CheckpointNumber, feeHeader: FeeHeader): Promise<StateOverride> {
|
|
874
|
+
const { epochDuration, proofSubmissionEpochs } = await this.getRollupConstants();
|
|
875
|
+
const roundaboutSize = BigInt(epochDuration * (proofSubmissionEpochs + 1) + 1);
|
|
876
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
877
|
+
|
|
878
|
+
// tempCheckpointLogs is at offset 2 in RollupStore
|
|
879
|
+
const tempCheckpointLogsMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 2n;
|
|
880
|
+
|
|
881
|
+
// Solidity mapping slot: keccak256(abi.encode(key, baseSlot))
|
|
882
|
+
const structBaseSlot = hexToBigInt(
|
|
883
|
+
keccak256(
|
|
884
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsMappingBase]),
|
|
885
|
+
),
|
|
886
|
+
);
|
|
887
|
+
|
|
888
|
+
// feeHeader is the 7th field (offset 6) in CompressedTempCheckpointLog
|
|
889
|
+
const feeHeaderSlot = structBaseSlot + 6n;
|
|
890
|
+
const compressed = RollupContract.compressFeeHeader(feeHeader);
|
|
891
|
+
|
|
892
|
+
return [
|
|
893
|
+
{
|
|
894
|
+
address: this.address,
|
|
895
|
+
stateDiff: [
|
|
896
|
+
{
|
|
897
|
+
slot: `0x${feeHeaderSlot.toString(16).padStart(64, '0')}`,
|
|
898
|
+
value: `0x${compressed.toString(16).padStart(64, '0')}`,
|
|
899
|
+
},
|
|
900
|
+
],
|
|
901
|
+
},
|
|
902
|
+
];
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* Returns a state override that sets archives[checkpointNumber] to the given archive value.
|
|
907
|
+
* Used when simulating a canProposeAtTime call where the local archive differs from L1
|
|
908
|
+
* (e.g. pipelining where the parent checkpoint hasn't landed on L1 yet).
|
|
909
|
+
*/
|
|
910
|
+
public makeArchiveOverride(checkpointNumber: CheckpointNumber, archive: Fr): StateOverride {
|
|
911
|
+
const archivesMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 1n;
|
|
912
|
+
const archiveSlot = hexToBigInt(
|
|
913
|
+
keccak256(
|
|
914
|
+
encodeAbiParameters(
|
|
915
|
+
[{ type: 'uint256' }, { type: 'uint256' }],
|
|
916
|
+
[BigInt(checkpointNumber), archivesMappingBase],
|
|
917
|
+
),
|
|
918
|
+
),
|
|
919
|
+
);
|
|
920
|
+
return [
|
|
921
|
+
{
|
|
922
|
+
address: this.address,
|
|
923
|
+
stateDiff: [
|
|
924
|
+
{
|
|
925
|
+
slot: `0x${archiveSlot.toString(16).padStart(64, '0')}`,
|
|
926
|
+
value: archive.toString(),
|
|
927
|
+
},
|
|
928
|
+
],
|
|
929
|
+
},
|
|
930
|
+
];
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/** Merges multiple StateOverride arrays, combining stateDiff entries for the same address. */
|
|
934
|
+
public static mergeStateOverrides(...overrides: StateOverride[]): StateOverride {
|
|
935
|
+
type StateDiffEntry = { slot: `0x${string}`; value: `0x${string}` };
|
|
936
|
+
const byAddress = new Map<string, { address: `0x${string}`; balance?: bigint; stateDiff: StateDiffEntry[] }>();
|
|
937
|
+
for (const override of overrides) {
|
|
938
|
+
for (const entry of override) {
|
|
939
|
+
const key = entry.address.toLowerCase();
|
|
940
|
+
const existing = byAddress.get(key);
|
|
941
|
+
if (existing) {
|
|
942
|
+
existing.stateDiff.push(...(entry.stateDiff ?? []));
|
|
943
|
+
if (entry.balance !== undefined) {
|
|
944
|
+
existing.balance = entry.balance;
|
|
945
|
+
}
|
|
946
|
+
} else {
|
|
947
|
+
byAddress.set(key, {
|
|
948
|
+
address: entry.address,
|
|
949
|
+
balance: entry.balance,
|
|
950
|
+
stateDiff: [...(entry.stateDiff ?? [])],
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return [...byAddress.values()];
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/** Compresses a FeeHeader into a uint256 matching FeeHeaderLib.compress() in FeeStructs.sol. */
|
|
959
|
+
public static compressFeeHeader(feeHeader: FeeHeader): bigint {
|
|
960
|
+
const MASK_48_BITS = (1n << 48n) - 1n;
|
|
961
|
+
const MASK_64_BITS = (1n << 64n) - 1n;
|
|
962
|
+
const MASK_63_BITS = (1n << 63n) - 1n;
|
|
963
|
+
|
|
964
|
+
let value = BigInt(feeHeader.manaUsed) & ((1n << 32n) - 1n); // bits [0:31]
|
|
965
|
+
value |= (feeHeader.excessMana < MASK_48_BITS ? feeHeader.excessMana : MASK_48_BITS) << 32n; // bits [32:79]
|
|
966
|
+
value |= (BigInt(feeHeader.ethPerFeeAsset) & MASK_48_BITS) << 80n; // bits [80:127]
|
|
967
|
+
value |= (feeHeader.congestionCost < MASK_64_BITS ? feeHeader.congestionCost : MASK_64_BITS) << 128n; // bits [128:191]
|
|
968
|
+
value |= (feeHeader.proverCost < MASK_63_BITS ? feeHeader.proverCost : MASK_63_BITS) << 192n; // bits [192:254]
|
|
969
|
+
value |= 1n << 255n; // preheat flag
|
|
970
|
+
return value;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
/** Computes the fee header for a child checkpoint given parent fee header and child data.
|
|
974
|
+
* Must stay in sync with Solidity FeeLib.sol (computeNewEthPerFeeAsset, clampedAdd). */
|
|
975
|
+
public static computeChildFeeHeader(
|
|
976
|
+
parentFeeHeader: FeeHeader,
|
|
977
|
+
childManaUsed: bigint,
|
|
978
|
+
feeAssetPriceModifier: bigint,
|
|
979
|
+
manaTarget: bigint,
|
|
980
|
+
): FeeHeader {
|
|
981
|
+
const MIN_ETH_PER_FEE_ASSET = 100n;
|
|
982
|
+
const MAX_ETH_PER_FEE_ASSET = 100_000_000_000_000n; // 1e14, matches FeeLib.sol
|
|
983
|
+
|
|
984
|
+
// excessMana = clampedAdd(parent.excessMana + parent.manaUsed, -manaTarget)
|
|
985
|
+
const sum = parentFeeHeader.excessMana + parentFeeHeader.manaUsed;
|
|
986
|
+
const excessMana = sum > manaTarget ? sum - manaTarget : 0n;
|
|
987
|
+
|
|
988
|
+
// ethPerFeeAsset = computeNewEthPerFeeAsset(max(parent.ethPerFeeAsset, MIN), modifier)
|
|
989
|
+
const parentPrice =
|
|
990
|
+
parentFeeHeader.ethPerFeeAsset > MIN_ETH_PER_FEE_ASSET ? parentFeeHeader.ethPerFeeAsset : MIN_ETH_PER_FEE_ASSET;
|
|
991
|
+
let newPrice: bigint;
|
|
992
|
+
if (feeAssetPriceModifier >= 0n) {
|
|
993
|
+
newPrice = (parentPrice * (10_000n + feeAssetPriceModifier)) / 10_000n;
|
|
994
|
+
} else {
|
|
995
|
+
const absMod = -feeAssetPriceModifier;
|
|
996
|
+
newPrice = (parentPrice * (10_000n - absMod)) / 10_000n;
|
|
997
|
+
}
|
|
998
|
+
if (newPrice < MIN_ETH_PER_FEE_ASSET) {
|
|
999
|
+
newPrice = MIN_ETH_PER_FEE_ASSET;
|
|
1000
|
+
}
|
|
1001
|
+
if (newPrice > MAX_ETH_PER_FEE_ASSET) {
|
|
1002
|
+
newPrice = MAX_ETH_PER_FEE_ASSET;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
return {
|
|
1006
|
+
excessMana,
|
|
1007
|
+
manaUsed: childManaUsed,
|
|
1008
|
+
ethPerFeeAsset: newPrice,
|
|
1009
|
+
congestionCost: 0n,
|
|
1010
|
+
proverCost: 0n,
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
|
|
587
1014
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
588
1015
|
public buildInvalidateBadAttestationRequest(
|
|
589
|
-
checkpointNumber:
|
|
1016
|
+
checkpointNumber: CheckpointNumber,
|
|
590
1017
|
attestationsAndSigners: ViemCommitteeAttestations,
|
|
591
1018
|
committee: EthAddress[],
|
|
592
1019
|
invalidIndex: number,
|
|
593
1020
|
): L1TxRequest {
|
|
594
1021
|
return {
|
|
595
1022
|
to: this.address,
|
|
1023
|
+
abi: RollupAbi,
|
|
596
1024
|
data: encodeFunctionData({
|
|
597
1025
|
abi: RollupAbi,
|
|
598
1026
|
functionName: 'invalidateBadAttestation',
|
|
@@ -608,12 +1036,13 @@ export class RollupContract {
|
|
|
608
1036
|
|
|
609
1037
|
/** Creates a request to Rollup#invalidateInsufficientAttestations to be simulated or sent */
|
|
610
1038
|
public buildInvalidateInsufficientAttestationsRequest(
|
|
611
|
-
checkpointNumber:
|
|
1039
|
+
checkpointNumber: CheckpointNumber,
|
|
612
1040
|
attestationsAndSigners: ViemCommitteeAttestations,
|
|
613
1041
|
committee: EthAddress[],
|
|
614
1042
|
): L1TxRequest {
|
|
615
1043
|
return {
|
|
616
1044
|
to: this.address,
|
|
1045
|
+
abi: RollupAbi,
|
|
617
1046
|
data: encodeFunctionData({
|
|
618
1047
|
abi: RollupAbi,
|
|
619
1048
|
functionName: 'invalidateInsufficientAttestations',
|
|
@@ -630,90 +1059,133 @@ export class RollupContract {
|
|
|
630
1059
|
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]);
|
|
631
1060
|
}
|
|
632
1061
|
|
|
633
|
-
|
|
634
|
-
return this.rollup.read.
|
|
1062
|
+
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean, stateOverride?: StateOverride): Promise<bigint> {
|
|
1063
|
+
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset], { stateOverride });
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
async getManaMinFeeComponentsAt(timestamp: bigint, inFeeAsset: boolean): Promise<ManaMinFeeComponents> {
|
|
1067
|
+
const result = await this.rollup.read.getManaMinFeeComponentsAt([timestamp, inFeeAsset]);
|
|
1068
|
+
return {
|
|
1069
|
+
sequencerCost: result.sequencerCost,
|
|
1070
|
+
proverCost: result.proverCost,
|
|
1071
|
+
congestionCost: result.congestionCost,
|
|
1072
|
+
congestionMultiplier: result.congestionMultiplier,
|
|
1073
|
+
};
|
|
635
1074
|
}
|
|
636
1075
|
|
|
637
1076
|
async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
|
|
638
1077
|
return SlotNumber.fromBigInt(await this.rollup.read.getSlotAt([timestamp]));
|
|
639
1078
|
}
|
|
640
1079
|
|
|
641
|
-
async status(checkpointNumber:
|
|
1080
|
+
async status(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise<RollupStatusResponse> {
|
|
642
1081
|
await checkBlockTag(options?.blockNumber, this.client);
|
|
643
|
-
|
|
1082
|
+
const result = await this.rollup.read.status([BigInt(checkpointNumber)], options);
|
|
1083
|
+
return {
|
|
1084
|
+
provenCheckpointNumber: CheckpointNumber.fromBigInt(result[0]),
|
|
1085
|
+
provenArchive: Fr.fromString(result[1]),
|
|
1086
|
+
pendingCheckpointNumber: CheckpointNumber.fromBigInt(result[2]),
|
|
1087
|
+
pendingArchive: Fr.fromString(result[3]),
|
|
1088
|
+
archiveOfMyCheckpoint: Fr.fromString(result[4]),
|
|
1089
|
+
};
|
|
644
1090
|
}
|
|
645
1091
|
|
|
646
|
-
async canPruneAtTime(timestamp: bigint, options?: { blockNumber?: bigint }) {
|
|
1092
|
+
async canPruneAtTime(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<boolean> {
|
|
647
1093
|
await checkBlockTag(options?.blockNumber, this.client);
|
|
648
1094
|
return this.rollup.read.canPruneAtTime([timestamp], options);
|
|
649
1095
|
}
|
|
650
1096
|
|
|
651
|
-
archive() {
|
|
652
|
-
return this.rollup.read.archive();
|
|
1097
|
+
async archive(): Promise<Fr> {
|
|
1098
|
+
return Fr.fromString(await this.rollup.read.archive());
|
|
653
1099
|
}
|
|
654
1100
|
|
|
655
|
-
archiveAt(checkpointNumber:
|
|
656
|
-
return this.rollup.read.archiveAt([checkpointNumber]);
|
|
1101
|
+
async archiveAt(checkpointNumber: CheckpointNumber): Promise<Fr> {
|
|
1102
|
+
return Fr.fromString(await this.rollup.read.archiveAt([BigInt(checkpointNumber)]));
|
|
657
1103
|
}
|
|
658
1104
|
|
|
659
|
-
getSequencerRewards(address: Hex | EthAddress) {
|
|
1105
|
+
getSequencerRewards(address: Hex | EthAddress): Promise<bigint> {
|
|
660
1106
|
if (address instanceof EthAddress) {
|
|
661
1107
|
address = address.toString();
|
|
662
1108
|
}
|
|
663
1109
|
return this.rollup.read.getSequencerRewards([address]);
|
|
664
1110
|
}
|
|
665
1111
|
|
|
666
|
-
getSpecificProverRewardsForEpoch(epoch: bigint, prover: Hex | EthAddress) {
|
|
1112
|
+
getSpecificProverRewardsForEpoch(epoch: bigint, prover: Hex | EthAddress): Promise<bigint> {
|
|
667
1113
|
if (prover instanceof EthAddress) {
|
|
668
1114
|
prover = prover.toString();
|
|
669
1115
|
}
|
|
670
1116
|
return this.rollup.read.getSpecificProverRewardsForEpoch([epoch, prover]);
|
|
671
1117
|
}
|
|
672
1118
|
|
|
673
|
-
async getAttesters() {
|
|
1119
|
+
async getAttesters(timestamp?: bigint): Promise<EthAddress[]> {
|
|
674
1120
|
const attesterSize = await this.getActiveAttesterCount();
|
|
675
1121
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
676
|
-
const ts = (await this.client.getBlock()).timestamp;
|
|
677
|
-
|
|
678
|
-
const indices = Array.from({ length: Number(attesterSize) }, (_, i) => BigInt(i));
|
|
1122
|
+
const ts = timestamp ?? (await this.client.getBlock()).timestamp;
|
|
1123
|
+
const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i));
|
|
679
1124
|
const chunks = chunk(indices, 1000);
|
|
680
1125
|
|
|
681
|
-
|
|
1126
|
+
const results = await Promise.all(chunks.map(chunk => gse.getAttestersFromIndicesAtTime(this.address, ts, chunk)));
|
|
1127
|
+
return results.flat().map(addr => EthAddress.fromString(addr));
|
|
682
1128
|
}
|
|
683
1129
|
|
|
684
|
-
getAttesterView(address: Hex | EthAddress) {
|
|
1130
|
+
async getAttesterView(address: Hex | EthAddress): Promise<AttesterView> {
|
|
685
1131
|
if (address instanceof EthAddress) {
|
|
686
1132
|
address = address.toString();
|
|
687
1133
|
}
|
|
688
|
-
|
|
1134
|
+
const result = await this.rollup.read.getAttesterView([address]);
|
|
1135
|
+
return {
|
|
1136
|
+
status: result.status as AttesterStatus,
|
|
1137
|
+
effectiveBalance: result.effectiveBalance,
|
|
1138
|
+
exit: {
|
|
1139
|
+
withdrawalId: result.exit.withdrawalId,
|
|
1140
|
+
amount: result.exit.amount,
|
|
1141
|
+
exitableAt: result.exit.exitableAt,
|
|
1142
|
+
recipientOrWithdrawer: EthAddress.fromString(result.exit.recipientOrWithdrawer),
|
|
1143
|
+
isRecipient: result.exit.isRecipient,
|
|
1144
|
+
exists: result.exit.exists,
|
|
1145
|
+
},
|
|
1146
|
+
config: {
|
|
1147
|
+
publicKey: {
|
|
1148
|
+
x: result.config.publicKey.x,
|
|
1149
|
+
y: result.config.publicKey.y,
|
|
1150
|
+
},
|
|
1151
|
+
withdrawer: EthAddress.fromString(result.config.withdrawer),
|
|
1152
|
+
},
|
|
1153
|
+
};
|
|
689
1154
|
}
|
|
690
1155
|
|
|
691
|
-
getStatus(address: Hex | EthAddress) {
|
|
1156
|
+
async getStatus(address: Hex | EthAddress): Promise<AttesterStatus> {
|
|
692
1157
|
if (address instanceof EthAddress) {
|
|
693
1158
|
address = address.toString();
|
|
694
1159
|
}
|
|
695
|
-
return this.rollup.read.getStatus([address]);
|
|
1160
|
+
return (await this.rollup.read.getStatus([address])) as AttesterStatus;
|
|
696
1161
|
}
|
|
697
1162
|
|
|
698
|
-
getBlobCommitmentsHash(checkpointNumber:
|
|
699
|
-
return this.rollup.read.getBlobCommitmentsHash([checkpointNumber]);
|
|
1163
|
+
async getBlobCommitmentsHash(checkpointNumber: CheckpointNumber): Promise<Buffer32> {
|
|
1164
|
+
return Buffer32.fromString(await this.rollup.read.getBlobCommitmentsHash([BigInt(checkpointNumber)]));
|
|
700
1165
|
}
|
|
701
1166
|
|
|
702
|
-
getCurrentBlobCommitmentsHash() {
|
|
703
|
-
return this.rollup.read.getCurrentBlobCommitmentsHash();
|
|
1167
|
+
async getCurrentBlobCommitmentsHash(): Promise<Buffer32> {
|
|
1168
|
+
return Buffer32.fromString(await this.rollup.read.getCurrentBlobCommitmentsHash());
|
|
704
1169
|
}
|
|
705
1170
|
|
|
706
|
-
getStakingAsset() {
|
|
707
|
-
return this.rollup.read.getStakingAsset();
|
|
1171
|
+
async getStakingAsset(): Promise<EthAddress> {
|
|
1172
|
+
return EthAddress.fromString(await this.rollup.read.getStakingAsset());
|
|
708
1173
|
}
|
|
709
1174
|
|
|
710
|
-
getRewardConfig() {
|
|
711
|
-
|
|
1175
|
+
async getRewardConfig(): Promise<RewardConfig> {
|
|
1176
|
+
const result = await this.rollup.read.getRewardConfig();
|
|
1177
|
+
return {
|
|
1178
|
+
rewardDistributor: EthAddress.fromString(result.rewardDistributor),
|
|
1179
|
+
sequencerBps: BigInt(result.sequencerBps),
|
|
1180
|
+
booster: EthAddress.fromString(result.booster),
|
|
1181
|
+
checkpointReward: result.checkpointReward,
|
|
1182
|
+
};
|
|
712
1183
|
}
|
|
713
1184
|
|
|
714
1185
|
setupEpoch(l1TxUtils: L1TxUtils) {
|
|
715
1186
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
716
1187
|
to: this.address,
|
|
1188
|
+
abi: RollupAbi,
|
|
717
1189
|
data: encodeFunctionData({
|
|
718
1190
|
abi: RollupAbi,
|
|
719
1191
|
functionName: 'setupEpoch',
|
|
@@ -725,6 +1197,7 @@ export class RollupContract {
|
|
|
725
1197
|
vote(l1TxUtils: L1TxUtils, proposalId: bigint) {
|
|
726
1198
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
727
1199
|
to: this.address,
|
|
1200
|
+
abi: RollupAbi,
|
|
728
1201
|
data: encodeFunctionData({
|
|
729
1202
|
abi: RollupAbi,
|
|
730
1203
|
functionName: 'vote',
|
|
@@ -752,7 +1225,7 @@ export class RollupContract {
|
|
|
752
1225
|
}
|
|
753
1226
|
|
|
754
1227
|
public listenToCheckpointInvalidated(
|
|
755
|
-
callback: (args: { checkpointNumber:
|
|
1228
|
+
callback: (args: { checkpointNumber: CheckpointNumber; event: Log }) => unknown,
|
|
756
1229
|
): WatchContractEventReturnType {
|
|
757
1230
|
return this.rollup.watchEvent.CheckpointInvalidated(
|
|
758
1231
|
{},
|
|
@@ -761,7 +1234,7 @@ export class RollupContract {
|
|
|
761
1234
|
for (const log of logs) {
|
|
762
1235
|
const args = log.args;
|
|
763
1236
|
if (args.checkpointNumber !== undefined) {
|
|
764
|
-
callback({ checkpointNumber: args.checkpointNumber });
|
|
1237
|
+
callback({ checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber), event: log });
|
|
765
1238
|
}
|
|
766
1239
|
}
|
|
767
1240
|
},
|
|
@@ -793,4 +1266,83 @@ export class RollupContract {
|
|
|
793
1266
|
},
|
|
794
1267
|
);
|
|
795
1268
|
}
|
|
1269
|
+
|
|
1270
|
+
/**
|
|
1271
|
+
* Fetches OwnershipTransferred events emitted on the L1 block this rollup was deployed on.
|
|
1272
|
+
* The Rollup inherits from Ownable and emits this event in its constructor, so the event
|
|
1273
|
+
* is guaranteed to exist on `l1StartBlock` for any correctly deployed rollup. Used as a
|
|
1274
|
+
* probe to detect RPC nodes that prune historical logs.
|
|
1275
|
+
*/
|
|
1276
|
+
async getOwnershipTransferredEventsAtDeploy() {
|
|
1277
|
+
const l1StartBlock = await this.getL1StartBlock();
|
|
1278
|
+
return await this.rollup.getEvents.OwnershipTransferred({}, { fromBlock: l1StartBlock, toBlock: l1StartBlock });
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
/** Fetches CheckpointProposed events within the given block range. */
|
|
1282
|
+
async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
|
|
1283
|
+
const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
|
|
1284
|
+
return logs
|
|
1285
|
+
.filter(log => log.blockNumber! >= fromBlock && log.blockNumber! <= toBlock)
|
|
1286
|
+
.map(log => ({
|
|
1287
|
+
l1BlockNumber: log.blockNumber!,
|
|
1288
|
+
l1BlockHash: Buffer32.fromString(log.blockHash!),
|
|
1289
|
+
l1TransactionHash: log.transactionHash!,
|
|
1290
|
+
args: {
|
|
1291
|
+
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
1292
|
+
archive: Fr.fromString(log.args.archive!),
|
|
1293
|
+
versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
|
|
1294
|
+
attestationsHash: (() => {
|
|
1295
|
+
if (!log.args.attestationsHash) {
|
|
1296
|
+
throw new Error(
|
|
1297
|
+
`CheckpointProposed event missing attestationsHash for checkpoint ${log.args.checkpointNumber}`,
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
return Buffer32.fromString(log.args.attestationsHash);
|
|
1301
|
+
})(),
|
|
1302
|
+
payloadDigest: (() => {
|
|
1303
|
+
if (!log.args.payloadDigest) {
|
|
1304
|
+
throw new Error(
|
|
1305
|
+
`CheckpointProposed event missing payloadDigest for checkpoint ${log.args.checkpointNumber}`,
|
|
1306
|
+
);
|
|
1307
|
+
}
|
|
1308
|
+
return Buffer32.fromString(log.args.payloadDigest);
|
|
1309
|
+
})(),
|
|
1310
|
+
},
|
|
1311
|
+
}));
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
/** Packs pending and proven checkpoint numbers into the chain tips storage format. */
|
|
1315
|
+
static packChainTips(pendingCheckpointNumber: bigint, provenCheckpointNumber: bigint): bigint {
|
|
1316
|
+
return (pendingCheckpointNumber << 128n) | (provenCheckpointNumber & ((1n << 128n) - 1n));
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
/** Storage slot for the chain tips (offset 0 within the STF storage struct). */
|
|
1320
|
+
static get chainTipsStorageSlot(): bigint {
|
|
1321
|
+
return BigInt(RollupContract.stfStorageSlot);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/**
|
|
1325
|
+
* Computes the storage slot for a field within a tempCheckpointLog entry.
|
|
1326
|
+
* @param checkpointNumber - The checkpoint number
|
|
1327
|
+
* @param field - The field within the CompressedTempCheckpointLog struct
|
|
1328
|
+
*/
|
|
1329
|
+
async getTempCheckpointLogStorageSlot(
|
|
1330
|
+
checkpointNumber: CheckpointNumber,
|
|
1331
|
+
field: TempCheckpointLogField,
|
|
1332
|
+
): Promise<bigint> {
|
|
1333
|
+
const fieldOffset = BigInt(field);
|
|
1334
|
+
const [epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
1335
|
+
this.getEpochDuration(),
|
|
1336
|
+
this.getProofSubmissionEpochs(),
|
|
1337
|
+
]);
|
|
1338
|
+
const roundaboutSize = BigInt(epochDuration) * (BigInt(proofSubmissionEpochs) + 1n) + 1n;
|
|
1339
|
+
const tempCheckpointLogsBase = BigInt(RollupContract.stfStorageSlot) + 2n;
|
|
1340
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
1341
|
+
const entryBase = BigInt(
|
|
1342
|
+
keccak256(
|
|
1343
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsBase]),
|
|
1344
|
+
),
|
|
1345
|
+
);
|
|
1346
|
+
return entryBase + fieldOffset;
|
|
1347
|
+
}
|
|
796
1348
|
}
|