@aztec/ethereum 0.0.1-commit.b655e406 → 0.0.1-commit.b6e433891
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/account.d.ts +1 -1
- package/dest/chain.d.ts +1 -1
- package/dest/client.d.ts +10 -2
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +13 -3
- package/dest/config.d.ts +24 -68
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +67 -380
- package/dest/constants.d.ts +1 -1
- package/dest/contracts/empire_base.d.ts +9 -5
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/empire_base.js +1 -1
- package/dest/contracts/empire_slashing_proposer.d.ts +8 -4
- package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.js +39 -17
- package/dest/contracts/errors.d.ts +1 -1
- package/dest/contracts/errors.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.d.ts +6 -5
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.js +11 -9
- package/dest/contracts/fee_asset_price_oracle.d.ts +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/fee_juice.d.ts +1 -1
- package/dest/contracts/fee_juice.d.ts.map +1 -1
- package/dest/contracts/governance.d.ts +18 -16
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +14 -4
- package/dest/contracts/governance_proposer.d.ts +8 -4
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +412 -11
- package/dest/contracts/gse.d.ts +1 -1
- package/dest/contracts/gse.d.ts.map +1 -1
- package/dest/contracts/inbox.d.ts +24 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +36 -1
- package/dest/contracts/index.d.ts +4 -1
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +3 -0
- 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 +2 -2
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +2 -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 +208 -123
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +807 -188
- package/dest/contracts/slasher_contract.d.ts +1 -1
- package/dest/contracts/slasher_contract.d.ts.map +1 -1
- package/dest/contracts/tally_slashing_proposer.d.ts +9 -7
- package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/tally_slashing_proposer.js +11 -4
- package/dest/contracts/utils.d.ts +1 -1
- package/dest/deploy_aztec_l1_contracts.d.ts +259 -0
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
- package/dest/deploy_aztec_l1_contracts.js +413 -0
- package/dest/deploy_l1_contract.d.ts +68 -0
- package/dest/deploy_l1_contract.d.ts.map +1 -0
- package/dest/deploy_l1_contract.js +312 -0
- package/dest/eth-signer/eth-signer.d.ts +1 -1
- package/dest/eth-signer/index.d.ts +1 -1
- package/dest/forwarder_proxy.d.ts +32 -0
- package/dest/forwarder_proxy.d.ts.map +1 -0
- package/dest/forwarder_proxy.js +93 -0
- package/dest/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 +7608 -2048
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_contract_addresses.d.ts +3 -3
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +3 -3
- package/dest/l1_reader.d.ts +5 -1
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +12 -1
- package/dest/l1_tx_utils/config.d.ts +11 -5
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +43 -7
- 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 +18 -8
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +75 -46
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +19 -30
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +63 -167
- package/dest/l1_tx_utils/signer.d.ts +1 -1
- 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/l1_tx_utils/types.d.ts +1 -1
- package/dest/l1_tx_utils/types.d.ts.map +1 -1
- package/dest/l1_tx_utils/utils.d.ts +1 -1
- package/dest/l1_types.d.ts +1 -1
- package/dest/publisher_manager.d.ts +3 -2
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +2 -2
- package/dest/queries.d.ts +2 -2
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +16 -6
- package/dest/test/chain_monitor.d.ts +47 -25
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +66 -38
- package/dest/test/eth_cheat_codes.d.ts +11 -3
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +11 -3
- package/dest/test/eth_cheat_codes_with_state.d.ts +1 -1
- package/dest/test/eth_cheat_codes_with_state.d.ts.map +1 -1
- package/dest/test/index.d.ts +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 +17 -13
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +62 -38
- package/dest/test/start_anvil.d.ts +18 -2
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +129 -28
- package/dest/test/upgrade_utils.d.ts +1 -1
- package/dest/test/upgrade_utils.js +2 -2
- package/dest/types.d.ts +57 -2
- package/dest/types.d.ts.map +1 -1
- package/dest/utils.d.ts +16 -3
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +80 -12
- package/dest/zkPassportVerifierAddress.d.ts +1 -1
- package/package.json +34 -16
- package/src/client.ts +10 -2
- package/src/config.ts +86 -460
- package/src/contracts/README.md +157 -0
- package/src/contracts/empire_base.ts +8 -5
- package/src/contracts/empire_slashing_proposer.ts +38 -32
- 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 +26 -6
- package/src/contracts/inbox.ts +55 -3
- package/src/contracts/index.ts +3 -0
- package/src/contracts/log.ts +13 -0
- package/src/contracts/multicall.ts +5 -2
- package/src/contracts/outbox.ts +98 -0
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +485 -162
- package/src/contracts/tally_slashing_proposer.ts +15 -8
- package/src/deploy_aztec_l1_contracts.ts +650 -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_contract_addresses.ts +22 -20
- package/src/l1_reader.ts +21 -1
- package/src/l1_tx_utils/config.ts +52 -11
- 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 +84 -36
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +77 -213
- package/src/{test → l1_tx_utils}/tx_delayer.ts +82 -52
- package/src/publisher_manager.ts +4 -2
- package/src/queries.ts +17 -6
- package/src/test/chain_monitor.ts +110 -51
- package/src/test/eth_cheat_codes.ts +9 -3
- package/src/test/index.ts +0 -2
- package/src/test/rollup_cheat_codes.ts +63 -43
- package/src/test/start_anvil.ts +156 -27
- package/src/test/upgrade_utils.ts +2 -2
- package/src/types.ts +62 -0
- package/src/utils.ts +100 -15
- package/dest/deploy_l1_contracts.d.ts +0 -226
- package/dest/deploy_l1_contracts.d.ts.map +0 -1
- package/dest/deploy_l1_contracts.js +0 -1473
- package/dest/index.d.ts +0 -18
- package/dest/index.d.ts.map +0 -1
- package/dest/index.js +0 -17
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +0 -26
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +0 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +0 -26
- package/dest/test/delayed_tx_utils.d.ts +0 -13
- package/dest/test/delayed_tx_utils.d.ts.map +0 -1
- package/dest/test/delayed_tx_utils.js +0 -28
- package/dest/test/tx_delayer.d.ts +0 -36
- package/dest/test/tx_delayer.d.ts.map +0 -1
- package/src/deploy_l1_contracts.ts +0 -1849
- package/src/index.ts +0 -17
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
- package/src/test/delayed_tx_utils.ts +0 -52
package/src/contracts/rollup.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
1
4
|
import { memoize } from '@aztec/foundation/decorators';
|
|
2
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
6
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
7
|
+
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
8
|
+
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
4
9
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
5
10
|
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
6
11
|
|
|
@@ -18,7 +23,7 @@ import {
|
|
|
18
23
|
} from 'viem';
|
|
19
24
|
|
|
20
25
|
import { getPublicClient } from '../client.js';
|
|
21
|
-
import type {
|
|
26
|
+
import type { DeployAztecL1ContractsReturnType } from '../deploy_aztec_l1_contracts.js';
|
|
22
27
|
import type { L1ContractAddresses } from '../l1_contract_addresses.js';
|
|
23
28
|
import type { L1ReaderConfig } from '../l1_reader.js';
|
|
24
29
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
@@ -26,6 +31,7 @@ import type { ViemClient } from '../types.js';
|
|
|
26
31
|
import { formatViemError } from '../utils.js';
|
|
27
32
|
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
28
33
|
import { GSEContract } from './gse.js';
|
|
34
|
+
import type { L1EventLog } from './log.js';
|
|
29
35
|
import { SlasherContract } from './slasher_contract.js';
|
|
30
36
|
import { TallySlashingProposerContract } from './tally_slashing_proposer.js';
|
|
31
37
|
import { checkBlockTag } from './utils.js';
|
|
@@ -56,12 +62,16 @@ export type L1RollupContractAddresses = Pick<
|
|
|
56
62
|
export type EpochProofPublicInputArgs = {
|
|
57
63
|
previousArchive: `0x${string}`;
|
|
58
64
|
endArchive: `0x${string}`;
|
|
65
|
+
outHash: `0x${string}`;
|
|
59
66
|
proverId: `0x${string}`;
|
|
60
67
|
};
|
|
61
68
|
|
|
62
69
|
export type ViemHeader = {
|
|
63
70
|
lastArchiveRoot: `0x${string}`;
|
|
64
|
-
|
|
71
|
+
blockHeadersHash: `0x${string}`;
|
|
72
|
+
blobsHash: `0x${string}`;
|
|
73
|
+
inHash: `0x${string}`;
|
|
74
|
+
outHash: `0x${string}`;
|
|
65
75
|
slotNumber: bigint;
|
|
66
76
|
timestamp: bigint;
|
|
67
77
|
coinbase: `0x${string}`;
|
|
@@ -70,43 +80,144 @@ export type ViemHeader = {
|
|
|
70
80
|
totalManaUsed: bigint;
|
|
71
81
|
};
|
|
72
82
|
|
|
73
|
-
export type ViemContentCommitment = {
|
|
74
|
-
blobsHash: `0x${string}`;
|
|
75
|
-
inHash: `0x${string}`;
|
|
76
|
-
outHash: `0x${string}`;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
83
|
export type ViemGasFees = {
|
|
80
84
|
feePerDaGas: bigint;
|
|
81
85
|
feePerL2Gas: bigint;
|
|
82
86
|
};
|
|
83
87
|
|
|
84
|
-
export
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
export enum SlashingProposerType {
|
|
89
|
+
None = 0,
|
|
90
|
+
Tally = 1,
|
|
91
|
+
Empire = 2,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Status of a validator/attester in the staking system.
|
|
96
|
+
* Matches the Status enum in StakingLib.sol
|
|
97
|
+
*/
|
|
98
|
+
export enum AttesterStatus {
|
|
99
|
+
NONE = 0,
|
|
100
|
+
VALIDATING = 1,
|
|
101
|
+
ZOMBIE = 2,
|
|
102
|
+
EXITING = 3,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Fee header data for a checkpoint
|
|
107
|
+
*/
|
|
108
|
+
export type FeeHeader = {
|
|
109
|
+
excessMana: bigint;
|
|
110
|
+
manaUsed: bigint;
|
|
111
|
+
ethPerFeeAsset: bigint;
|
|
112
|
+
congestionCost: bigint;
|
|
113
|
+
proverCost: bigint;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Checkpoint log data returned from the rollup contract
|
|
118
|
+
*/
|
|
119
|
+
export type CheckpointLog = {
|
|
120
|
+
archive: Fr;
|
|
121
|
+
headerHash: Buffer32;
|
|
122
|
+
blobCommitmentsHash: Buffer32;
|
|
123
|
+
attestationsHash: Buffer32;
|
|
124
|
+
payloadDigest: Buffer32;
|
|
125
|
+
slotNumber: SlotNumber;
|
|
126
|
+
feeHeader: FeeHeader;
|
|
87
127
|
};
|
|
88
128
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
129
|
+
/**
|
|
130
|
+
* L1 fee data (base fee and blob fee)
|
|
131
|
+
*/
|
|
132
|
+
export type L1FeeData = {
|
|
133
|
+
baseFee: bigint;
|
|
134
|
+
blobFee: bigint;
|
|
93
135
|
};
|
|
94
136
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
137
|
+
/** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
|
|
138
|
+
export type ManaMinFeeComponents = {
|
|
139
|
+
sequencerCost: bigint;
|
|
140
|
+
proverCost: bigint;
|
|
141
|
+
congestionCost: bigint;
|
|
142
|
+
congestionMultiplier: bigint;
|
|
98
143
|
};
|
|
99
144
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Reward configuration for the rollup
|
|
147
|
+
*/
|
|
148
|
+
export type RewardConfig = {
|
|
149
|
+
rewardDistributor: EthAddress;
|
|
150
|
+
sequencerBps: bigint;
|
|
151
|
+
booster: EthAddress;
|
|
152
|
+
checkpointReward: bigint;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Exit information for a validator
|
|
157
|
+
*/
|
|
158
|
+
export type Exit = {
|
|
159
|
+
withdrawalId: bigint;
|
|
160
|
+
amount: bigint;
|
|
161
|
+
exitableAt: bigint;
|
|
162
|
+
recipientOrWithdrawer: EthAddress;
|
|
163
|
+
isRecipient: boolean;
|
|
164
|
+
exists: boolean;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Attester configuration including public key and withdrawer
|
|
169
|
+
*/
|
|
170
|
+
export type AttesterConfig = {
|
|
171
|
+
publicKey: {
|
|
172
|
+
x: bigint;
|
|
173
|
+
y: bigint;
|
|
174
|
+
};
|
|
175
|
+
withdrawer: EthAddress;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Complete view of an attester's state
|
|
180
|
+
*/
|
|
181
|
+
export type AttesterView = {
|
|
182
|
+
status: AttesterStatus;
|
|
183
|
+
effectiveBalance: bigint;
|
|
184
|
+
exit: Exit;
|
|
185
|
+
config: AttesterConfig;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Return for a status call
|
|
190
|
+
*/
|
|
191
|
+
export type RollupStatusResponse = {
|
|
192
|
+
provenCheckpointNumber: CheckpointNumber;
|
|
193
|
+
provenArchive: Fr;
|
|
194
|
+
pendingCheckpointNumber: CheckpointNumber;
|
|
195
|
+
pendingArchive: Fr;
|
|
196
|
+
archiveOfMyCheckpoint: Fr;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/** Arguments for the CheckpointProposed event. */
|
|
200
|
+
export type CheckpointProposedArgs = {
|
|
201
|
+
checkpointNumber: CheckpointNumber;
|
|
202
|
+
archive: Fr;
|
|
203
|
+
versionedBlobHashes: Buffer[];
|
|
204
|
+
/** Hash of attestations emitted in the CheckpointProposed event. */
|
|
205
|
+
attestationsHash: Buffer32;
|
|
206
|
+
/** Digest of the payload emitted in the CheckpointProposed event. */
|
|
207
|
+
payloadDigest: Buffer32;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
/** Log type for CheckpointProposed events. */
|
|
211
|
+
export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
105
212
|
|
|
106
213
|
export class RollupContract {
|
|
107
214
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
108
215
|
|
|
109
216
|
private static cachedStfStorageSlot: Hex | undefined;
|
|
217
|
+
private cachedEscapeHatch?: {
|
|
218
|
+
address: EthAddress;
|
|
219
|
+
contract: GetContractReturnType<typeof EscapeHatchAbi, ViemClient>;
|
|
220
|
+
};
|
|
110
221
|
|
|
111
222
|
static get checkBlobStorageSlot(): bigint {
|
|
112
223
|
const asString = RollupStorage.find(storage => storage.label === 'checkBlob')?.slot;
|
|
@@ -120,7 +231,7 @@ export class RollupContract {
|
|
|
120
231
|
return (RollupContract.cachedStfStorageSlot ??= keccak256(Buffer.from('aztec.stf.storage', 'utf-8')));
|
|
121
232
|
}
|
|
122
233
|
|
|
123
|
-
static getFromL1ContractsValues(deployL1ContractsValues:
|
|
234
|
+
static getFromL1ContractsValues(deployL1ContractsValues: DeployAztecL1ContractsReturnType) {
|
|
124
235
|
const {
|
|
125
236
|
l1Client,
|
|
126
237
|
l1ContractAddresses: { rollupAddress },
|
|
@@ -144,8 +255,8 @@ export class RollupContract {
|
|
|
144
255
|
this.rollup = getContract({ address, abi: RollupAbi, client });
|
|
145
256
|
}
|
|
146
257
|
|
|
147
|
-
getGSE() {
|
|
148
|
-
return this.rollup.read.getGSE();
|
|
258
|
+
async getGSE(): Promise<EthAddress> {
|
|
259
|
+
return EthAddress.fromString(await this.rollup.read.getGSE());
|
|
149
260
|
}
|
|
150
261
|
|
|
151
262
|
public get address() {
|
|
@@ -187,88 +298,107 @@ export class RollupContract {
|
|
|
187
298
|
}
|
|
188
299
|
|
|
189
300
|
@memoize
|
|
190
|
-
getL1StartBlock() {
|
|
301
|
+
getL1StartBlock(): Promise<bigint> {
|
|
191
302
|
return this.rollup.read.L1_BLOCK_AT_GENESIS();
|
|
192
303
|
}
|
|
193
304
|
|
|
194
305
|
@memoize
|
|
195
|
-
getL1GenesisTime() {
|
|
306
|
+
getL1GenesisTime(): Promise<bigint> {
|
|
196
307
|
return this.rollup.read.getGenesisTime();
|
|
197
308
|
}
|
|
198
309
|
|
|
199
310
|
@memoize
|
|
200
|
-
getProofSubmissionEpochs() {
|
|
201
|
-
return this.rollup.read.getProofSubmissionEpochs();
|
|
311
|
+
async getProofSubmissionEpochs(): Promise<number> {
|
|
312
|
+
return Number(await this.rollup.read.getProofSubmissionEpochs());
|
|
202
313
|
}
|
|
203
314
|
|
|
204
315
|
@memoize
|
|
205
|
-
getEpochDuration() {
|
|
206
|
-
return this.rollup.read.getEpochDuration();
|
|
316
|
+
async getEpochDuration(): Promise<number> {
|
|
317
|
+
return Number(await this.rollup.read.getEpochDuration());
|
|
207
318
|
}
|
|
208
319
|
|
|
209
320
|
@memoize
|
|
210
|
-
getSlotDuration() {
|
|
211
|
-
return this.rollup.read.getSlotDuration();
|
|
321
|
+
async getSlotDuration(): Promise<number> {
|
|
322
|
+
return Number(await this.rollup.read.getSlotDuration());
|
|
212
323
|
}
|
|
213
324
|
|
|
214
325
|
@memoize
|
|
215
|
-
getTargetCommitteeSize() {
|
|
216
|
-
return this.rollup.read.getTargetCommitteeSize();
|
|
326
|
+
async getTargetCommitteeSize(): Promise<number> {
|
|
327
|
+
return Number(await this.rollup.read.getTargetCommitteeSize());
|
|
217
328
|
}
|
|
218
329
|
|
|
219
330
|
@memoize
|
|
220
|
-
getEjectionThreshold() {
|
|
331
|
+
getEjectionThreshold(): Promise<bigint> {
|
|
221
332
|
return this.rollup.read.getEjectionThreshold();
|
|
222
333
|
}
|
|
223
334
|
|
|
224
335
|
@memoize
|
|
225
|
-
getLocalEjectionThreshold() {
|
|
336
|
+
getLocalEjectionThreshold(): Promise<bigint> {
|
|
226
337
|
return this.rollup.read.getLocalEjectionThreshold();
|
|
227
338
|
}
|
|
228
339
|
|
|
229
340
|
@memoize
|
|
230
|
-
|
|
231
|
-
return this.rollup.read.
|
|
341
|
+
async getLagInEpochsForValidatorSet(): Promise<number> {
|
|
342
|
+
return Number(await this.rollup.read.getLagInEpochsForValidatorSet());
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
@memoize
|
|
346
|
+
async getLagInEpochsForRandao(): Promise<number> {
|
|
347
|
+
return Number(await this.rollup.read.getLagInEpochsForRandao());
|
|
232
348
|
}
|
|
233
349
|
|
|
234
350
|
@memoize
|
|
235
|
-
getActivationThreshold() {
|
|
351
|
+
getActivationThreshold(): Promise<bigint> {
|
|
236
352
|
return this.rollup.read.getActivationThreshold();
|
|
237
353
|
}
|
|
238
354
|
|
|
239
355
|
@memoize
|
|
240
|
-
getExitDelay() {
|
|
241
|
-
return this.rollup.read.getExitDelay();
|
|
356
|
+
async getExitDelay(): Promise<number> {
|
|
357
|
+
return Number(await this.rollup.read.getExitDelay());
|
|
242
358
|
}
|
|
243
359
|
|
|
244
360
|
@memoize
|
|
245
|
-
getManaTarget() {
|
|
361
|
+
getManaTarget(): Promise<bigint> {
|
|
246
362
|
return this.rollup.read.getManaTarget();
|
|
247
363
|
}
|
|
248
364
|
|
|
249
365
|
@memoize
|
|
250
|
-
getProvingCostPerMana() {
|
|
366
|
+
getProvingCostPerMana(): Promise<bigint> {
|
|
251
367
|
return this.rollup.read.getProvingCostPerManaInEth();
|
|
252
368
|
}
|
|
253
369
|
|
|
254
370
|
@memoize
|
|
255
|
-
getProvingCostPerManaInFeeAsset() {
|
|
371
|
+
getProvingCostPerManaInFeeAsset(): Promise<bigint> {
|
|
256
372
|
return this.rollup.read.getProvingCostPerManaInFeeAsset();
|
|
257
373
|
}
|
|
258
374
|
|
|
259
375
|
@memoize
|
|
260
|
-
getManaLimit() {
|
|
376
|
+
getManaLimit(): Promise<bigint> {
|
|
261
377
|
return this.rollup.read.getManaLimit();
|
|
262
378
|
}
|
|
263
379
|
|
|
264
380
|
@memoize
|
|
265
|
-
getVersion() {
|
|
381
|
+
getVersion(): Promise<bigint> {
|
|
266
382
|
return this.rollup.read.getVersion();
|
|
267
383
|
}
|
|
268
384
|
|
|
269
385
|
@memoize
|
|
270
|
-
async getGenesisArchiveTreeRoot(): Promise
|
|
271
|
-
return await this.rollup.read.archiveAt([0n]);
|
|
386
|
+
async getGenesisArchiveTreeRoot(): Promise<Fr> {
|
|
387
|
+
return Fr.fromString(await this.rollup.read.archiveAt([0n]));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
@memoize
|
|
391
|
+
async getVkTreeRoot(): Promise<Fr> {
|
|
392
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 3n;
|
|
393
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
394
|
+
return Fr.fromString(value ?? '0x0');
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
@memoize
|
|
398
|
+
async getProtocolContractsHash(): Promise<Fr> {
|
|
399
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 4n;
|
|
400
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
401
|
+
return Fr.fromString(value ?? '0x0');
|
|
272
402
|
}
|
|
273
403
|
|
|
274
404
|
/**
|
|
@@ -283,44 +413,110 @@ export class RollupContract {
|
|
|
283
413
|
slotDuration: number;
|
|
284
414
|
epochDuration: number;
|
|
285
415
|
proofSubmissionEpochs: number;
|
|
416
|
+
targetCommitteeSize: number;
|
|
417
|
+
rollupManaLimit: number;
|
|
286
418
|
}> {
|
|
287
|
-
const [
|
|
419
|
+
const [
|
|
420
|
+
l1StartBlock,
|
|
421
|
+
l1GenesisTime,
|
|
422
|
+
slotDuration,
|
|
423
|
+
epochDuration,
|
|
424
|
+
proofSubmissionEpochs,
|
|
425
|
+
targetCommitteeSize,
|
|
426
|
+
rollupManaLimit,
|
|
427
|
+
] = await Promise.all([
|
|
288
428
|
this.getL1StartBlock(),
|
|
289
429
|
this.getL1GenesisTime(),
|
|
290
430
|
this.getSlotDuration(),
|
|
291
431
|
this.getEpochDuration(),
|
|
292
432
|
this.getProofSubmissionEpochs(),
|
|
433
|
+
this.getTargetCommitteeSize(),
|
|
434
|
+
this.getManaLimit(),
|
|
293
435
|
]);
|
|
294
436
|
return {
|
|
295
437
|
l1StartBlock,
|
|
296
438
|
l1GenesisTime,
|
|
297
|
-
slotDuration
|
|
439
|
+
slotDuration,
|
|
298
440
|
epochDuration: Number(epochDuration),
|
|
299
441
|
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
442
|
+
targetCommitteeSize,
|
|
443
|
+
rollupManaLimit: Number(rollupManaLimit),
|
|
300
444
|
};
|
|
301
445
|
}
|
|
302
446
|
|
|
303
|
-
getSlasherAddress() {
|
|
304
|
-
return this.rollup.read.getSlasher();
|
|
447
|
+
async getSlasherAddress(): Promise<EthAddress> {
|
|
448
|
+
return EthAddress.fromString(await this.rollup.read.getSlasher());
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Returns the configured escape hatch contract address, or zero if disabled.
|
|
453
|
+
*/
|
|
454
|
+
async getEscapeHatchAddress(): Promise<EthAddress> {
|
|
455
|
+
return EthAddress.fromString(await this.rollup.read.getEscapeHatch());
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
private async getEscapeHatchContract(): Promise<
|
|
459
|
+
GetContractReturnType<typeof EscapeHatchAbi, ViemClient> | undefined
|
|
460
|
+
> {
|
|
461
|
+
const escapeHatchAddress = await this.getEscapeHatchAddress();
|
|
462
|
+
if (escapeHatchAddress.isZero()) {
|
|
463
|
+
return undefined;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Cache the viem contract wrapper since it will be used frequently.
|
|
467
|
+
if (!this.cachedEscapeHatch || !this.cachedEscapeHatch.address.equals(escapeHatchAddress)) {
|
|
468
|
+
this.cachedEscapeHatch = {
|
|
469
|
+
address: escapeHatchAddress,
|
|
470
|
+
contract: getContract({
|
|
471
|
+
address: escapeHatchAddress.toString(),
|
|
472
|
+
abi: EscapeHatchAbi,
|
|
473
|
+
client: this.client,
|
|
474
|
+
}),
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return this.cachedEscapeHatch.contract;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Returns whether the escape hatch is open for the given epoch.
|
|
483
|
+
* If escape hatch is not configured, returns false.
|
|
484
|
+
*
|
|
485
|
+
* This function is intentionally defensive: any failure to query the escape hatch
|
|
486
|
+
* (RPC issues, transient errors, etc.) is treated as "closed" to avoid callers
|
|
487
|
+
* needing to sprinkle try/catch everywhere.
|
|
488
|
+
*/
|
|
489
|
+
async isEscapeHatchOpen(epoch: EpochNumber): Promise<boolean> {
|
|
490
|
+
try {
|
|
491
|
+
const escapeHatch = await this.getEscapeHatchContract();
|
|
492
|
+
if (!escapeHatch) {
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
|
|
497
|
+
return isOpen;
|
|
498
|
+
} catch {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
305
501
|
}
|
|
306
502
|
|
|
307
503
|
/**
|
|
308
504
|
* Returns a SlasherContract instance for interacting with the slasher contract.
|
|
309
505
|
*/
|
|
310
506
|
async getSlasherContract(): Promise<SlasherContract | undefined> {
|
|
311
|
-
const slasherAddress =
|
|
507
|
+
const slasherAddress = await this.getSlasherAddress();
|
|
312
508
|
if (slasherAddress.isZero()) {
|
|
313
509
|
return undefined;
|
|
314
510
|
}
|
|
315
511
|
return new SlasherContract(this.client, slasherAddress);
|
|
316
512
|
}
|
|
317
513
|
|
|
318
|
-
getOwner() {
|
|
319
|
-
return this.rollup.read.owner();
|
|
514
|
+
async getOwner(): Promise<EthAddress> {
|
|
515
|
+
return EthAddress.fromString(await this.rollup.read.owner());
|
|
320
516
|
}
|
|
321
517
|
|
|
322
|
-
getActiveAttesterCount() {
|
|
323
|
-
return this.rollup.read.getActiveAttesterCount();
|
|
518
|
+
async getActiveAttesterCount(): Promise<number> {
|
|
519
|
+
return Number(await this.rollup.read.getActiveAttesterCount());
|
|
324
520
|
}
|
|
325
521
|
|
|
326
522
|
public async getSlashingProposerAddress() {
|
|
@@ -331,31 +527,36 @@ export class RollupContract {
|
|
|
331
527
|
return await slasher.getProposer();
|
|
332
528
|
}
|
|
333
529
|
|
|
334
|
-
|
|
335
|
-
return this.rollup.read.
|
|
530
|
+
getCheckpointReward(): Promise<bigint> {
|
|
531
|
+
return this.rollup.read.getCheckpointReward();
|
|
336
532
|
}
|
|
337
533
|
|
|
338
|
-
|
|
339
|
-
return this.rollup.read.
|
|
534
|
+
async getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
535
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber());
|
|
340
536
|
}
|
|
341
537
|
|
|
342
|
-
|
|
343
|
-
|
|
538
|
+
async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
539
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
540
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
344
541
|
}
|
|
345
542
|
|
|
346
|
-
getSlotNumber() {
|
|
347
|
-
return this.rollup.read.getCurrentSlot();
|
|
543
|
+
async getSlotNumber(): Promise<SlotNumber> {
|
|
544
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot());
|
|
348
545
|
}
|
|
349
546
|
|
|
350
|
-
getL1FeesAt(timestamp: bigint) {
|
|
351
|
-
|
|
547
|
+
async getL1FeesAt(timestamp: bigint): Promise<L1FeeData> {
|
|
548
|
+
const result = await this.rollup.read.getL1FeesAt([timestamp]);
|
|
549
|
+
return {
|
|
550
|
+
baseFee: result.baseFee,
|
|
551
|
+
blobFee: result.blobFee,
|
|
552
|
+
};
|
|
352
553
|
}
|
|
353
554
|
|
|
354
|
-
|
|
355
|
-
return this.rollup.read.
|
|
555
|
+
getEthPerFeeAsset(): Promise<bigint> {
|
|
556
|
+
return this.rollup.read.getEthPerFeeAsset();
|
|
356
557
|
}
|
|
357
558
|
|
|
358
|
-
async getCommitteeAt(timestamp: bigint): Promise<
|
|
559
|
+
async getCommitteeAt(timestamp: bigint): Promise<EthAddress[] | undefined> {
|
|
359
560
|
const { result } = await this.client
|
|
360
561
|
.simulateContract({
|
|
361
562
|
address: this.address,
|
|
@@ -370,22 +571,22 @@ export class RollupContract {
|
|
|
370
571
|
throw e;
|
|
371
572
|
});
|
|
372
573
|
|
|
373
|
-
return result;
|
|
574
|
+
return result ? result.map(addr => EthAddress.fromString(addr)) : undefined;
|
|
374
575
|
}
|
|
375
576
|
|
|
376
|
-
getSampleSeedAt(timestamp: bigint) {
|
|
377
|
-
return this.rollup.read.getSampleSeedAt([timestamp]);
|
|
577
|
+
async getSampleSeedAt(timestamp: bigint): Promise<Buffer32> {
|
|
578
|
+
return Buffer32.fromBigInt(await this.rollup.read.getSampleSeedAt([timestamp]));
|
|
378
579
|
}
|
|
379
580
|
|
|
380
|
-
getCurrentSampleSeed() {
|
|
381
|
-
return this.rollup.read.getCurrentSampleSeed();
|
|
581
|
+
async getCurrentSampleSeed(): Promise<Buffer32> {
|
|
582
|
+
return Buffer32.fromBigInt(await this.rollup.read.getCurrentSampleSeed());
|
|
382
583
|
}
|
|
383
584
|
|
|
384
|
-
getCurrentEpoch() {
|
|
385
|
-
return this.rollup.read.getCurrentEpoch();
|
|
585
|
+
async getCurrentEpoch(): Promise<EpochNumber> {
|
|
586
|
+
return EpochNumber.fromBigInt(await this.rollup.read.getCurrentEpoch());
|
|
386
587
|
}
|
|
387
588
|
|
|
388
|
-
async getCurrentEpochCommittee(): Promise<
|
|
589
|
+
async getCurrentEpochCommittee(): Promise<EthAddress[] | undefined> {
|
|
389
590
|
const { result } = await this.client
|
|
390
591
|
.simulateContract({
|
|
391
592
|
address: this.address,
|
|
@@ -400,10 +601,10 @@ export class RollupContract {
|
|
|
400
601
|
throw e;
|
|
401
602
|
});
|
|
402
603
|
|
|
403
|
-
return result;
|
|
604
|
+
return result ? result.map(addr => EthAddress.fromString(addr)) : undefined;
|
|
404
605
|
}
|
|
405
606
|
|
|
406
|
-
async getCurrentProposer() {
|
|
607
|
+
async getCurrentProposer(): Promise<EthAddress> {
|
|
407
608
|
const { result } = await this.client.simulateContract({
|
|
408
609
|
address: this.address,
|
|
409
610
|
abi: RollupAbi,
|
|
@@ -411,10 +612,10 @@ export class RollupContract {
|
|
|
411
612
|
args: [],
|
|
412
613
|
});
|
|
413
614
|
|
|
414
|
-
return result;
|
|
615
|
+
return EthAddress.fromString(result);
|
|
415
616
|
}
|
|
416
617
|
|
|
417
|
-
async getProposerAt(timestamp: bigint) {
|
|
618
|
+
async getProposerAt(timestamp: bigint): Promise<EthAddress> {
|
|
418
619
|
const { result } = await this.client.simulateContract({
|
|
419
620
|
address: this.address,
|
|
420
621
|
abi: RollupAbi,
|
|
@@ -422,39 +623,73 @@ export class RollupContract {
|
|
|
422
623
|
args: [timestamp],
|
|
423
624
|
});
|
|
424
625
|
|
|
425
|
-
return result;
|
|
626
|
+
return EthAddress.fromString(result);
|
|
426
627
|
}
|
|
427
628
|
|
|
428
|
-
|
|
429
|
-
|
|
629
|
+
async getCheckpoint(checkpointNumber: CheckpointNumber): Promise<CheckpointLog> {
|
|
630
|
+
const result = await this.rollup.read.getCheckpoint([BigInt(checkpointNumber)]);
|
|
631
|
+
return {
|
|
632
|
+
archive: Fr.fromString(result.archive),
|
|
633
|
+
headerHash: Buffer32.fromString(result.headerHash),
|
|
634
|
+
blobCommitmentsHash: Buffer32.fromString(result.blobCommitmentsHash),
|
|
635
|
+
attestationsHash: Buffer32.fromString(result.attestationsHash),
|
|
636
|
+
payloadDigest: Buffer32.fromString(result.payloadDigest),
|
|
637
|
+
slotNumber: SlotNumber.fromBigInt(result.slotNumber),
|
|
638
|
+
feeHeader: {
|
|
639
|
+
excessMana: result.feeHeader.excessMana,
|
|
640
|
+
manaUsed: result.feeHeader.manaUsed,
|
|
641
|
+
ethPerFeeAsset: result.feeHeader.ethPerFeeAsset,
|
|
642
|
+
congestionCost: result.feeHeader.congestionCost,
|
|
643
|
+
proverCost: result.feeHeader.proverCost,
|
|
644
|
+
},
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/** Returns the pending checkpoint from the rollup contract */
|
|
649
|
+
getPendingCheckpoint() {
|
|
650
|
+
// We retry because of race conditions during prunes: we may get a pending checkpoint number which is immediately
|
|
651
|
+
// reorged out due to a prune happening, causing the subsequent getCheckpoint call to fail. So we try again in that case.
|
|
652
|
+
return retry(
|
|
653
|
+
async () => {
|
|
654
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber();
|
|
655
|
+
const pendingCheckpoint = await this.getCheckpoint(pendingCheckpointNumber);
|
|
656
|
+
return pendingCheckpoint;
|
|
657
|
+
},
|
|
658
|
+
'getting pending checkpoint',
|
|
659
|
+
makeBackoff([0.5, 0.5, 0.5]),
|
|
660
|
+
);
|
|
430
661
|
}
|
|
431
662
|
|
|
432
|
-
getTips() {
|
|
433
|
-
|
|
663
|
+
async getTips(): Promise<{ pending: CheckpointNumber; proven: CheckpointNumber }> {
|
|
664
|
+
const { pending, proven } = await this.rollup.read.getTips();
|
|
665
|
+
return {
|
|
666
|
+
pending: CheckpointNumber.fromBigInt(pending),
|
|
667
|
+
proven: CheckpointNumber.fromBigInt(proven),
|
|
668
|
+
};
|
|
434
669
|
}
|
|
435
670
|
|
|
436
|
-
getTimestampForSlot(slot:
|
|
437
|
-
return this.rollup.read.getTimestampForSlot([slot]);
|
|
671
|
+
getTimestampForSlot(slot: SlotNumber): Promise<bigint> {
|
|
672
|
+
return this.rollup.read.getTimestampForSlot([BigInt(slot)]);
|
|
438
673
|
}
|
|
439
674
|
|
|
440
|
-
getEntryQueueLength() {
|
|
441
|
-
return this.rollup.read.getEntryQueueLength();
|
|
675
|
+
async getEntryQueueLength(): Promise<number> {
|
|
676
|
+
return Number(await this.rollup.read.getEntryQueueLength());
|
|
442
677
|
}
|
|
443
678
|
|
|
444
|
-
getAvailableValidatorFlushes() {
|
|
445
|
-
return this.rollup.read.getAvailableValidatorFlushes();
|
|
679
|
+
async getAvailableValidatorFlushes(): Promise<number> {
|
|
680
|
+
return Number(await this.rollup.read.getAvailableValidatorFlushes());
|
|
446
681
|
}
|
|
447
682
|
|
|
448
|
-
getNextFlushableEpoch() {
|
|
449
|
-
return this.rollup.read.getNextFlushableEpoch();
|
|
683
|
+
async getNextFlushableEpoch(): Promise<EpochNumber> {
|
|
684
|
+
return EpochNumber.fromBigInt(await this.rollup.read.getNextFlushableEpoch());
|
|
450
685
|
}
|
|
451
686
|
|
|
452
|
-
getCurrentEpochNumber(): Promise<
|
|
453
|
-
return this.rollup.read.getCurrentEpoch();
|
|
687
|
+
async getCurrentEpochNumber(): Promise<EpochNumber> {
|
|
688
|
+
return EpochNumber.fromBigInt(await this.rollup.read.getCurrentEpoch());
|
|
454
689
|
}
|
|
455
690
|
|
|
456
|
-
|
|
457
|
-
return this.rollup.read.
|
|
691
|
+
async getEpochNumberForCheckpoint(checkpointNumber: CheckpointNumber): Promise<EpochNumber> {
|
|
692
|
+
return EpochNumber.fromBigInt(await this.rollup.read.getEpochForCheckpoint([BigInt(checkpointNumber)]));
|
|
458
693
|
}
|
|
459
694
|
|
|
460
695
|
async getRollupAddresses(): Promise<L1RollupContractAddresses> {
|
|
@@ -494,14 +729,15 @@ export class RollupContract {
|
|
|
494
729
|
return EthAddress.fromString(await this.rollup.read.getFeeAssetPortal());
|
|
495
730
|
}
|
|
496
731
|
|
|
497
|
-
public async getEpochNumberForSlotNumber(slotNumber:
|
|
498
|
-
return await this.rollup.read.getEpochAtSlot([slotNumber]);
|
|
732
|
+
public async getEpochNumberForSlotNumber(slotNumber: SlotNumber): Promise<EpochNumber> {
|
|
733
|
+
return EpochNumber.fromBigInt(await this.rollup.read.getEpochAtSlot([BigInt(slotNumber)]));
|
|
499
734
|
}
|
|
500
735
|
|
|
501
|
-
getEpochProofPublicInputs(
|
|
736
|
+
async getEpochProofPublicInputs(
|
|
502
737
|
args: readonly [bigint, bigint, EpochProofPublicInputArgs, readonly `0x${string}`[], `0x${string}`],
|
|
503
|
-
) {
|
|
504
|
-
|
|
738
|
+
): Promise<Fr[]> {
|
|
739
|
+
const result = await this.rollup.read.getEpochProofPublicInputs(args);
|
|
740
|
+
return result.map(Fr.fromString);
|
|
505
741
|
}
|
|
506
742
|
|
|
507
743
|
public async validateHeader(
|
|
@@ -538,53 +774,58 @@ export class RollupContract {
|
|
|
538
774
|
* @dev Throws if unable to propose
|
|
539
775
|
*
|
|
540
776
|
* @param archive - The archive that we expect to be current state
|
|
541
|
-
* @return [slot,
|
|
777
|
+
* @return [slot, checkpointNumber, timeOfNextL1Slot] - If you can propose, the L2 slot number, checkpoint number and
|
|
778
|
+
* timestamp of the next L1 block
|
|
542
779
|
* @throws otherwise
|
|
543
780
|
*/
|
|
544
|
-
public async
|
|
781
|
+
public async canProposeAt(
|
|
545
782
|
archive: Buffer,
|
|
546
783
|
account: `0x${string}` | Account,
|
|
547
|
-
slotDuration: bigint
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
slotDuration = BigInt(slotDuration);
|
|
552
|
-
}
|
|
784
|
+
slotDuration: bigint,
|
|
785
|
+
slotOffset: bigint,
|
|
786
|
+
opts: { forcePendingCheckpointNumber?: CheckpointNumber } = {},
|
|
787
|
+
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
553
788
|
const latestBlock = await this.client.getBlock();
|
|
554
|
-
const timeOfNextL1Slot = latestBlock.timestamp + slotDuration;
|
|
789
|
+
const timeOfNextL1Slot = latestBlock.timestamp + slotDuration + slotOffset;
|
|
555
790
|
const who = typeof account === 'string' ? account : account.address;
|
|
556
791
|
|
|
557
792
|
try {
|
|
558
793
|
const {
|
|
559
|
-
result: [slot,
|
|
794
|
+
result: [slot, checkpointNumber],
|
|
560
795
|
} = await this.client.simulateContract({
|
|
561
796
|
address: this.address,
|
|
562
797
|
abi: RollupAbi,
|
|
563
798
|
functionName: 'canProposeAtTime',
|
|
564
799
|
args: [timeOfNextL1Slot, `0x${archive.toString('hex')}`, who],
|
|
565
800
|
account,
|
|
566
|
-
stateOverride: await this.
|
|
801
|
+
stateOverride: await this.makePendingCheckpointNumberOverride(opts.forcePendingCheckpointNumber),
|
|
567
802
|
});
|
|
568
803
|
|
|
569
|
-
return {
|
|
804
|
+
return {
|
|
805
|
+
slot: SlotNumber.fromBigInt(slot),
|
|
806
|
+
checkpointNumber: CheckpointNumber.fromBigInt(checkpointNumber),
|
|
807
|
+
timeOfNextL1Slot,
|
|
808
|
+
};
|
|
570
809
|
} catch (err: unknown) {
|
|
571
810
|
throw formatViemError(err);
|
|
572
811
|
}
|
|
573
812
|
}
|
|
574
813
|
|
|
575
814
|
/**
|
|
576
|
-
* Returns a state override that sets the pending
|
|
577
|
-
* Requires querying the current state of the contract to get the current proven
|
|
815
|
+
* Returns a state override that sets the pending checkpoint number to the specified value. Useful for simulations.
|
|
816
|
+
* Requires querying the current state of the contract to get the current proven checkpoint number, as they are both
|
|
578
817
|
* stored in the same slot. If the argument is undefined, it returns an empty override.
|
|
579
818
|
*/
|
|
580
|
-
public async
|
|
581
|
-
|
|
819
|
+
public async makePendingCheckpointNumberOverride(
|
|
820
|
+
forcePendingCheckpointNumber: CheckpointNumber | undefined,
|
|
821
|
+
): Promise<StateOverride> {
|
|
822
|
+
if (forcePendingCheckpointNumber === undefined) {
|
|
582
823
|
return [];
|
|
583
824
|
}
|
|
584
825
|
const slot = RollupContract.stfStorageSlot;
|
|
585
826
|
const currentValue = await this.client.getStorageAt({ address: this.address, slot });
|
|
586
|
-
const
|
|
587
|
-
const newValue = (BigInt(
|
|
827
|
+
const currentProvenCheckpointNumber = currentValue ? hexToBigInt(currentValue) & ((1n << 128n) - 1n) : 0n;
|
|
828
|
+
const newValue = (BigInt(forcePendingCheckpointNumber) << 128n) | currentProvenCheckpointNumber;
|
|
588
829
|
return [
|
|
589
830
|
{
|
|
590
831
|
address: this.address,
|
|
@@ -595,18 +836,19 @@ export class RollupContract {
|
|
|
595
836
|
|
|
596
837
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
597
838
|
public buildInvalidateBadAttestationRequest(
|
|
598
|
-
|
|
839
|
+
checkpointNumber: CheckpointNumber,
|
|
599
840
|
attestationsAndSigners: ViemCommitteeAttestations,
|
|
600
841
|
committee: EthAddress[],
|
|
601
842
|
invalidIndex: number,
|
|
602
843
|
): L1TxRequest {
|
|
603
844
|
return {
|
|
604
845
|
to: this.address,
|
|
846
|
+
abi: RollupAbi,
|
|
605
847
|
data: encodeFunctionData({
|
|
606
848
|
abi: RollupAbi,
|
|
607
849
|
functionName: 'invalidateBadAttestation',
|
|
608
850
|
args: [
|
|
609
|
-
BigInt(
|
|
851
|
+
BigInt(checkpointNumber),
|
|
610
852
|
attestationsAndSigners,
|
|
611
853
|
committee.map(addr => addr.toString()),
|
|
612
854
|
BigInt(invalidIndex),
|
|
@@ -617,112 +859,157 @@ export class RollupContract {
|
|
|
617
859
|
|
|
618
860
|
/** Creates a request to Rollup#invalidateInsufficientAttestations to be simulated or sent */
|
|
619
861
|
public buildInvalidateInsufficientAttestationsRequest(
|
|
620
|
-
|
|
862
|
+
checkpointNumber: CheckpointNumber,
|
|
621
863
|
attestationsAndSigners: ViemCommitteeAttestations,
|
|
622
864
|
committee: EthAddress[],
|
|
623
865
|
): L1TxRequest {
|
|
624
866
|
return {
|
|
625
867
|
to: this.address,
|
|
868
|
+
abi: RollupAbi,
|
|
626
869
|
data: encodeFunctionData({
|
|
627
870
|
abi: RollupAbi,
|
|
628
871
|
functionName: 'invalidateInsufficientAttestations',
|
|
629
|
-
args: [BigInt(
|
|
872
|
+
args: [BigInt(checkpointNumber), attestationsAndSigners, committee.map(addr => addr.toString())],
|
|
630
873
|
}),
|
|
631
874
|
};
|
|
632
875
|
}
|
|
633
876
|
|
|
634
877
|
/** Calls getHasSubmitted directly. Returns whether the given prover has submitted a proof with the given length for the given epoch. */
|
|
635
|
-
public getHasSubmittedProof(epochNumber:
|
|
878
|
+
public getHasSubmittedProof(epochNumber: EpochNumber, numberOfCheckpointsInEpoch: number, prover: Hex | EthAddress) {
|
|
636
879
|
if (prover instanceof EthAddress) {
|
|
637
880
|
prover = prover.toString();
|
|
638
881
|
}
|
|
639
|
-
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(
|
|
882
|
+
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]);
|
|
640
883
|
}
|
|
641
884
|
|
|
642
|
-
|
|
643
|
-
return this.rollup.read.
|
|
885
|
+
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean): Promise<bigint> {
|
|
886
|
+
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset]);
|
|
644
887
|
}
|
|
645
888
|
|
|
646
|
-
|
|
647
|
-
|
|
889
|
+
async getManaMinFeeComponentsAt(timestamp: bigint, inFeeAsset: boolean): Promise<ManaMinFeeComponents> {
|
|
890
|
+
const result = await this.rollup.read.getManaMinFeeComponentsAt([timestamp, inFeeAsset]);
|
|
891
|
+
return {
|
|
892
|
+
sequencerCost: result.sequencerCost,
|
|
893
|
+
proverCost: result.proverCost,
|
|
894
|
+
congestionCost: result.congestionCost,
|
|
895
|
+
congestionMultiplier: result.congestionMultiplier,
|
|
896
|
+
};
|
|
648
897
|
}
|
|
649
898
|
|
|
650
|
-
async
|
|
899
|
+
async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
|
|
900
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getSlotAt([timestamp]));
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
async status(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise<RollupStatusResponse> {
|
|
651
904
|
await checkBlockTag(options?.blockNumber, this.client);
|
|
652
|
-
|
|
905
|
+
const result = await this.rollup.read.status([BigInt(checkpointNumber)], options);
|
|
906
|
+
return {
|
|
907
|
+
provenCheckpointNumber: CheckpointNumber.fromBigInt(result[0]),
|
|
908
|
+
provenArchive: Fr.fromString(result[1]),
|
|
909
|
+
pendingCheckpointNumber: CheckpointNumber.fromBigInt(result[2]),
|
|
910
|
+
pendingArchive: Fr.fromString(result[3]),
|
|
911
|
+
archiveOfMyCheckpoint: Fr.fromString(result[4]),
|
|
912
|
+
};
|
|
653
913
|
}
|
|
654
914
|
|
|
655
|
-
async canPruneAtTime(timestamp: bigint, options?: { blockNumber?: bigint }) {
|
|
915
|
+
async canPruneAtTime(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<boolean> {
|
|
656
916
|
await checkBlockTag(options?.blockNumber, this.client);
|
|
657
917
|
return this.rollup.read.canPruneAtTime([timestamp], options);
|
|
658
918
|
}
|
|
659
919
|
|
|
660
|
-
archive() {
|
|
661
|
-
return this.rollup.read.archive();
|
|
920
|
+
async archive(): Promise<Fr> {
|
|
921
|
+
return Fr.fromString(await this.rollup.read.archive());
|
|
662
922
|
}
|
|
663
923
|
|
|
664
|
-
archiveAt(
|
|
665
|
-
return this.rollup.read.archiveAt([
|
|
924
|
+
async archiveAt(checkpointNumber: CheckpointNumber): Promise<Fr> {
|
|
925
|
+
return Fr.fromString(await this.rollup.read.archiveAt([BigInt(checkpointNumber)]));
|
|
666
926
|
}
|
|
667
927
|
|
|
668
|
-
getSequencerRewards(address: Hex | EthAddress) {
|
|
928
|
+
getSequencerRewards(address: Hex | EthAddress): Promise<bigint> {
|
|
669
929
|
if (address instanceof EthAddress) {
|
|
670
930
|
address = address.toString();
|
|
671
931
|
}
|
|
672
932
|
return this.rollup.read.getSequencerRewards([address]);
|
|
673
933
|
}
|
|
674
934
|
|
|
675
|
-
getSpecificProverRewardsForEpoch(epoch: bigint, prover: Hex | EthAddress) {
|
|
935
|
+
getSpecificProverRewardsForEpoch(epoch: bigint, prover: Hex | EthAddress): Promise<bigint> {
|
|
676
936
|
if (prover instanceof EthAddress) {
|
|
677
937
|
prover = prover.toString();
|
|
678
938
|
}
|
|
679
939
|
return this.rollup.read.getSpecificProverRewardsForEpoch([epoch, prover]);
|
|
680
940
|
}
|
|
681
941
|
|
|
682
|
-
async getAttesters() {
|
|
942
|
+
async getAttesters(): Promise<EthAddress[]> {
|
|
683
943
|
const attesterSize = await this.getActiveAttesterCount();
|
|
684
944
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
685
945
|
const ts = (await this.client.getBlock()).timestamp;
|
|
686
946
|
|
|
687
|
-
const indices = Array.from({ length:
|
|
947
|
+
const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i));
|
|
688
948
|
const chunks = chunk(indices, 1000);
|
|
689
949
|
|
|
690
|
-
|
|
950
|
+
const results = await Promise.all(chunks.map(chunk => gse.getAttestersFromIndicesAtTime(this.address, ts, chunk)));
|
|
951
|
+
return results.flat().map(addr => EthAddress.fromString(addr));
|
|
691
952
|
}
|
|
692
953
|
|
|
693
|
-
getAttesterView(address: Hex | EthAddress) {
|
|
954
|
+
async getAttesterView(address: Hex | EthAddress): Promise<AttesterView> {
|
|
694
955
|
if (address instanceof EthAddress) {
|
|
695
956
|
address = address.toString();
|
|
696
957
|
}
|
|
697
|
-
|
|
958
|
+
const result = await this.rollup.read.getAttesterView([address]);
|
|
959
|
+
return {
|
|
960
|
+
status: result.status as AttesterStatus,
|
|
961
|
+
effectiveBalance: result.effectiveBalance,
|
|
962
|
+
exit: {
|
|
963
|
+
withdrawalId: result.exit.withdrawalId,
|
|
964
|
+
amount: result.exit.amount,
|
|
965
|
+
exitableAt: result.exit.exitableAt,
|
|
966
|
+
recipientOrWithdrawer: EthAddress.fromString(result.exit.recipientOrWithdrawer),
|
|
967
|
+
isRecipient: result.exit.isRecipient,
|
|
968
|
+
exists: result.exit.exists,
|
|
969
|
+
},
|
|
970
|
+
config: {
|
|
971
|
+
publicKey: {
|
|
972
|
+
x: result.config.publicKey.x,
|
|
973
|
+
y: result.config.publicKey.y,
|
|
974
|
+
},
|
|
975
|
+
withdrawer: EthAddress.fromString(result.config.withdrawer),
|
|
976
|
+
},
|
|
977
|
+
};
|
|
698
978
|
}
|
|
699
979
|
|
|
700
|
-
getStatus(address: Hex | EthAddress) {
|
|
980
|
+
async getStatus(address: Hex | EthAddress): Promise<AttesterStatus> {
|
|
701
981
|
if (address instanceof EthAddress) {
|
|
702
982
|
address = address.toString();
|
|
703
983
|
}
|
|
704
|
-
return this.rollup.read.getStatus([address]);
|
|
984
|
+
return (await this.rollup.read.getStatus([address])) as AttesterStatus;
|
|
705
985
|
}
|
|
706
986
|
|
|
707
|
-
getBlobCommitmentsHash(
|
|
708
|
-
return this.rollup.read.getBlobCommitmentsHash([
|
|
987
|
+
async getBlobCommitmentsHash(checkpointNumber: CheckpointNumber): Promise<Buffer32> {
|
|
988
|
+
return Buffer32.fromString(await this.rollup.read.getBlobCommitmentsHash([BigInt(checkpointNumber)]));
|
|
709
989
|
}
|
|
710
990
|
|
|
711
|
-
getCurrentBlobCommitmentsHash() {
|
|
712
|
-
return this.rollup.read.getCurrentBlobCommitmentsHash();
|
|
991
|
+
async getCurrentBlobCommitmentsHash(): Promise<Buffer32> {
|
|
992
|
+
return Buffer32.fromString(await this.rollup.read.getCurrentBlobCommitmentsHash());
|
|
713
993
|
}
|
|
714
994
|
|
|
715
|
-
getStakingAsset() {
|
|
716
|
-
return this.rollup.read.getStakingAsset();
|
|
995
|
+
async getStakingAsset(): Promise<EthAddress> {
|
|
996
|
+
return EthAddress.fromString(await this.rollup.read.getStakingAsset());
|
|
717
997
|
}
|
|
718
998
|
|
|
719
|
-
getRewardConfig() {
|
|
720
|
-
|
|
999
|
+
async getRewardConfig(): Promise<RewardConfig> {
|
|
1000
|
+
const result = await this.rollup.read.getRewardConfig();
|
|
1001
|
+
return {
|
|
1002
|
+
rewardDistributor: EthAddress.fromString(result.rewardDistributor),
|
|
1003
|
+
sequencerBps: BigInt(result.sequencerBps),
|
|
1004
|
+
booster: EthAddress.fromString(result.booster),
|
|
1005
|
+
checkpointReward: result.checkpointReward,
|
|
1006
|
+
};
|
|
721
1007
|
}
|
|
722
1008
|
|
|
723
1009
|
setupEpoch(l1TxUtils: L1TxUtils) {
|
|
724
1010
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
725
1011
|
to: this.address,
|
|
1012
|
+
abi: RollupAbi,
|
|
726
1013
|
data: encodeFunctionData({
|
|
727
1014
|
abi: RollupAbi,
|
|
728
1015
|
functionName: 'setupEpoch',
|
|
@@ -734,6 +1021,7 @@ export class RollupContract {
|
|
|
734
1021
|
vote(l1TxUtils: L1TxUtils, proposalId: bigint) {
|
|
735
1022
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
736
1023
|
to: this.address,
|
|
1024
|
+
abi: RollupAbi,
|
|
737
1025
|
data: encodeFunctionData({
|
|
738
1026
|
abi: RollupAbi,
|
|
739
1027
|
functionName: 'vote',
|
|
@@ -760,15 +1048,17 @@ export class RollupContract {
|
|
|
760
1048
|
);
|
|
761
1049
|
}
|
|
762
1050
|
|
|
763
|
-
public
|
|
764
|
-
|
|
1051
|
+
public listenToCheckpointInvalidated(
|
|
1052
|
+
callback: (args: { checkpointNumber: CheckpointNumber }) => unknown,
|
|
1053
|
+
): WatchContractEventReturnType {
|
|
1054
|
+
return this.rollup.watchEvent.CheckpointInvalidated(
|
|
765
1055
|
{},
|
|
766
1056
|
{
|
|
767
1057
|
onLogs: logs => {
|
|
768
1058
|
for (const log of logs) {
|
|
769
1059
|
const args = log.args;
|
|
770
|
-
if (args.
|
|
771
|
-
callback({
|
|
1060
|
+
if (args.checkpointNumber !== undefined) {
|
|
1061
|
+
callback({ checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber) });
|
|
772
1062
|
}
|
|
773
1063
|
}
|
|
774
1064
|
},
|
|
@@ -800,4 +1090,37 @@ export class RollupContract {
|
|
|
800
1090
|
},
|
|
801
1091
|
);
|
|
802
1092
|
}
|
|
1093
|
+
|
|
1094
|
+
/** Fetches CheckpointProposed events within the given block range. */
|
|
1095
|
+
async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
|
|
1096
|
+
const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
|
|
1097
|
+
return logs
|
|
1098
|
+
.filter(log => log.blockNumber! >= fromBlock && log.blockNumber! <= toBlock)
|
|
1099
|
+
.map(log => ({
|
|
1100
|
+
l1BlockNumber: log.blockNumber!,
|
|
1101
|
+
l1BlockHash: Buffer32.fromString(log.blockHash!),
|
|
1102
|
+
l1TransactionHash: log.transactionHash!,
|
|
1103
|
+
args: {
|
|
1104
|
+
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
1105
|
+
archive: Fr.fromString(log.args.archive!),
|
|
1106
|
+
versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
|
|
1107
|
+
attestationsHash: (() => {
|
|
1108
|
+
if (!log.args.attestationsHash) {
|
|
1109
|
+
throw new Error(
|
|
1110
|
+
`CheckpointProposed event missing attestationsHash for checkpoint ${log.args.checkpointNumber}`,
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
return Buffer32.fromString(log.args.attestationsHash);
|
|
1114
|
+
})(),
|
|
1115
|
+
payloadDigest: (() => {
|
|
1116
|
+
if (!log.args.payloadDigest) {
|
|
1117
|
+
throw new Error(
|
|
1118
|
+
`CheckpointProposed event missing payloadDigest for checkpoint ${log.args.checkpointNumber}`,
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
return Buffer32.fromString(log.args.payloadDigest);
|
|
1122
|
+
})(),
|
|
1123
|
+
},
|
|
1124
|
+
}));
|
|
1125
|
+
}
|
|
803
1126
|
}
|