@aztec/ethereum 4.0.0-nightly.20260112 → 4.0.0-nightly.20260114
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/config.d.ts +11 -28
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +36 -55
- package/dest/contracts/inbox.d.ts +18 -1
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +32 -1
- package/dest/contracts/index.d.ts +2 -1
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +1 -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/rollup.d.ts +17 -1
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +18 -0
- package/dest/deploy_aztec_l1_contracts.d.ts +12 -2
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +62 -12
- package/dest/generated/l1-contracts-defaults.d.ts +29 -0
- package/dest/generated/l1-contracts-defaults.d.ts.map +1 -0
- package/dest/generated/l1-contracts-defaults.js +29 -0
- package/dest/l1_artifacts.d.ts +448 -40
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/package.json +6 -5
- package/src/config.ts +41 -54
- package/src/contracts/README.md +157 -0
- package/src/contracts/inbox.ts +48 -1
- package/src/contracts/index.ts +1 -0
- package/src/contracts/log.ts +13 -0
- package/src/contracts/rollup.ts +35 -0
- package/src/deploy_aztec_l1_contracts.ts +63 -14
- package/src/generated/l1-contracts-defaults.ts +31 -0
package/src/config.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ConfigMappingsType,
|
|
3
|
-
// type NetworkNames,
|
|
4
3
|
bigintConfigHelper,
|
|
5
4
|
booleanConfigHelper,
|
|
6
5
|
enumConfigHelper,
|
|
7
6
|
getConfigFromMappings,
|
|
7
|
+
getDefaultConfig,
|
|
8
8
|
numberConfigHelper,
|
|
9
9
|
optionalNumberConfigHelper,
|
|
10
10
|
} from '@aztec/foundation/config';
|
|
11
11
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
12
12
|
|
|
13
|
+
import { l1ContractsDefaultEnv } from './generated/l1-contracts-defaults.js';
|
|
13
14
|
import { type L1TxUtilsConfig, l1TxUtilsConfigMappings } from './l1_tx_utils/config.js';
|
|
14
15
|
|
|
15
16
|
export type GenesisStateConfig = {
|
|
@@ -76,116 +77,96 @@ export type L1ContractsConfig = {
|
|
|
76
77
|
exitDelaySeconds: number;
|
|
77
78
|
} & L1TxUtilsConfig;
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
lagInEpochsForValidatorSet: 2,
|
|
85
|
-
lagInEpochsForRandao: 2, // For PROD, this value should be > lagInEpochsForValidatorSet
|
|
86
|
-
inboxLag: 1, // Default inbox lag to prevent sequencer DOS attacks
|
|
87
|
-
aztecProofSubmissionEpochs: 1, // you have a full epoch to submit a proof after the epoch to prove ends
|
|
88
|
-
activationThreshold: 100n * 10n ** 18n,
|
|
89
|
-
ejectionThreshold: 50n * 10n ** 18n,
|
|
90
|
-
localEjectionThreshold: 98n * 10n ** 18n,
|
|
91
|
-
slashAmountSmall: 10n * 10n ** 18n,
|
|
92
|
-
slashAmountMedium: 20n * 10n ** 18n,
|
|
93
|
-
slashAmountLarge: 50n * 10n ** 18n,
|
|
94
|
-
slashingRoundSizeInEpochs: 4,
|
|
95
|
-
slashingLifetimeInRounds: 5,
|
|
96
|
-
slashingExecutionDelayInRounds: 0, // round N may be submitted in round N + 1
|
|
97
|
-
slashingVetoer: EthAddress.ZERO,
|
|
98
|
-
governanceProposerRoundSize: 300,
|
|
99
|
-
manaTarget: BigInt(100e6),
|
|
100
|
-
provingCostPerMana: BigInt(100),
|
|
101
|
-
exitDelaySeconds: 2 * 24 * 60 * 60,
|
|
102
|
-
slasherFlavor: 'tally' as const,
|
|
103
|
-
slashingOffsetInRounds: 2,
|
|
104
|
-
slashingDisableDuration: 5 * 24 * 60 * 60, // 5 days in seconds
|
|
105
|
-
} satisfies L1ContractsConfig;
|
|
106
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Config mappings for L1ContractsConfig.
|
|
82
|
+
* Default values come from generated l1-contracts-defaults.json (source: defaults.yml).
|
|
83
|
+
* Real deployments use forge scripts which require explicit env vars (vm.envUint).
|
|
84
|
+
*/
|
|
107
85
|
export const l1ContractsConfigMappings: ConfigMappingsType<L1ContractsConfig> = {
|
|
108
86
|
ethereumSlotDuration: {
|
|
109
87
|
env: 'ETHEREUM_SLOT_DURATION',
|
|
110
88
|
description: 'How many seconds an L1 slot lasts.',
|
|
111
|
-
...numberConfigHelper(
|
|
89
|
+
...numberConfigHelper(l1ContractsDefaultEnv.ETHEREUM_SLOT_DURATION),
|
|
112
90
|
},
|
|
113
91
|
aztecSlotDuration: {
|
|
114
92
|
env: 'AZTEC_SLOT_DURATION',
|
|
115
93
|
description: 'How many seconds an L2 slots lasts (must be multiple of ethereum slot duration).',
|
|
116
|
-
...numberConfigHelper(
|
|
94
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_SLOT_DURATION),
|
|
117
95
|
},
|
|
118
96
|
aztecEpochDuration: {
|
|
119
97
|
env: 'AZTEC_EPOCH_DURATION',
|
|
120
98
|
description: `How many L2 slots an epoch lasts (maximum AZTEC_MAX_EPOCH_DURATION).`,
|
|
121
|
-
...numberConfigHelper(
|
|
99
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_EPOCH_DURATION),
|
|
122
100
|
},
|
|
123
101
|
aztecTargetCommitteeSize: {
|
|
124
102
|
env: 'AZTEC_TARGET_COMMITTEE_SIZE',
|
|
125
103
|
description: 'The target validator committee size.',
|
|
126
|
-
...numberConfigHelper(
|
|
104
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_TARGET_COMMITTEE_SIZE),
|
|
127
105
|
},
|
|
128
106
|
lagInEpochsForValidatorSet: {
|
|
129
107
|
env: 'AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET',
|
|
130
108
|
description: 'The number of epochs to lag behind the current epoch for validator selection.',
|
|
131
|
-
...numberConfigHelper(
|
|
109
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET),
|
|
132
110
|
},
|
|
133
111
|
lagInEpochsForRandao: {
|
|
134
112
|
env: 'AZTEC_LAG_IN_EPOCHS_FOR_RANDAO',
|
|
135
113
|
description: 'The number of epochs to lag behind the current epoch for randao selection.',
|
|
136
|
-
...numberConfigHelper(
|
|
114
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_LAG_IN_EPOCHS_FOR_RANDAO),
|
|
137
115
|
},
|
|
138
116
|
inboxLag: {
|
|
139
117
|
env: 'AZTEC_INBOX_LAG',
|
|
140
118
|
description: 'The number of checkpoints to lag in the inbox (prevents sequencer DOS attacks).',
|
|
141
|
-
...numberConfigHelper(
|
|
119
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_INBOX_LAG),
|
|
142
120
|
},
|
|
143
121
|
aztecProofSubmissionEpochs: {
|
|
144
122
|
env: 'AZTEC_PROOF_SUBMISSION_EPOCHS',
|
|
145
123
|
description: 'The number of epochs after an epoch ends that proofs are still accepted.',
|
|
146
|
-
...numberConfigHelper(
|
|
124
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_PROOF_SUBMISSION_EPOCHS),
|
|
147
125
|
},
|
|
148
126
|
activationThreshold: {
|
|
149
127
|
env: 'AZTEC_ACTIVATION_THRESHOLD',
|
|
150
128
|
description: 'The deposit amount for a validator',
|
|
151
|
-
...bigintConfigHelper(
|
|
129
|
+
...bigintConfigHelper(BigInt(l1ContractsDefaultEnv.AZTEC_ACTIVATION_THRESHOLD)),
|
|
152
130
|
},
|
|
153
131
|
ejectionThreshold: {
|
|
154
132
|
env: 'AZTEC_EJECTION_THRESHOLD',
|
|
155
133
|
description: 'The minimum stake for a validator.',
|
|
156
|
-
...bigintConfigHelper(
|
|
134
|
+
...bigintConfigHelper(BigInt(l1ContractsDefaultEnv.AZTEC_EJECTION_THRESHOLD)),
|
|
157
135
|
},
|
|
158
136
|
localEjectionThreshold: {
|
|
159
137
|
env: 'AZTEC_LOCAL_EJECTION_THRESHOLD',
|
|
160
138
|
description:
|
|
161
139
|
'The local ejection threshold for a validator. Stricter than ejectionThreshold but local to a specific rollup',
|
|
162
|
-
...bigintConfigHelper(
|
|
140
|
+
...bigintConfigHelper(BigInt(l1ContractsDefaultEnv.AZTEC_LOCAL_EJECTION_THRESHOLD)),
|
|
163
141
|
},
|
|
164
142
|
slashingOffsetInRounds: {
|
|
165
143
|
env: 'AZTEC_SLASHING_OFFSET_IN_ROUNDS',
|
|
166
144
|
description:
|
|
167
145
|
'How many slashing rounds back we slash (ie when slashing in round N, we slash for offenses committed during epochs of round N-offset)',
|
|
168
|
-
...numberConfigHelper(
|
|
146
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_SLASHING_OFFSET_IN_ROUNDS),
|
|
169
147
|
},
|
|
170
148
|
slasherFlavor: {
|
|
171
149
|
env: 'AZTEC_SLASHER_FLAVOR',
|
|
172
150
|
description: 'Type of slasher proposer (empire, tally, or none)',
|
|
173
|
-
...enumConfigHelper(
|
|
151
|
+
...enumConfigHelper(
|
|
152
|
+
['empire', 'tally', 'none'] as const,
|
|
153
|
+
l1ContractsDefaultEnv.AZTEC_SLASHER_FLAVOR as 'empire' | 'tally' | 'none',
|
|
154
|
+
),
|
|
174
155
|
},
|
|
175
156
|
slashAmountSmall: {
|
|
176
157
|
env: 'AZTEC_SLASH_AMOUNT_SMALL',
|
|
177
158
|
description: 'Small slashing amount for light offenses',
|
|
178
|
-
...bigintConfigHelper(
|
|
159
|
+
...bigintConfigHelper(BigInt(l1ContractsDefaultEnv.AZTEC_SLASH_AMOUNT_SMALL)),
|
|
179
160
|
},
|
|
180
161
|
slashAmountMedium: {
|
|
181
162
|
env: 'AZTEC_SLASH_AMOUNT_MEDIUM',
|
|
182
163
|
description: 'Medium slashing amount for moderate offenses',
|
|
183
|
-
...bigintConfigHelper(
|
|
164
|
+
...bigintConfigHelper(BigInt(l1ContractsDefaultEnv.AZTEC_SLASH_AMOUNT_MEDIUM)),
|
|
184
165
|
},
|
|
185
166
|
slashAmountLarge: {
|
|
186
167
|
env: 'AZTEC_SLASH_AMOUNT_LARGE',
|
|
187
168
|
description: 'Large slashing amount for severe offenses',
|
|
188
|
-
...bigintConfigHelper(
|
|
169
|
+
...bigintConfigHelper(BigInt(l1ContractsDefaultEnv.AZTEC_SLASH_AMOUNT_LARGE)),
|
|
189
170
|
},
|
|
190
171
|
slashingQuorum: {
|
|
191
172
|
env: 'AZTEC_SLASHING_QUORUM',
|
|
@@ -195,28 +176,28 @@ export const l1ContractsConfigMappings: ConfigMappingsType<L1ContractsConfig> =
|
|
|
195
176
|
slashingRoundSizeInEpochs: {
|
|
196
177
|
env: 'AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS',
|
|
197
178
|
description: 'The slashing round size',
|
|
198
|
-
...numberConfigHelper(
|
|
179
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS),
|
|
199
180
|
},
|
|
200
181
|
slashingLifetimeInRounds: {
|
|
201
182
|
env: 'AZTEC_SLASHING_LIFETIME_IN_ROUNDS',
|
|
202
183
|
description: 'The slashing lifetime in rounds',
|
|
203
|
-
...numberConfigHelper(
|
|
184
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_SLASHING_LIFETIME_IN_ROUNDS),
|
|
204
185
|
},
|
|
205
186
|
slashingExecutionDelayInRounds: {
|
|
206
187
|
env: 'AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS',
|
|
207
188
|
description: 'The slashing execution delay in rounds',
|
|
208
|
-
...numberConfigHelper(
|
|
189
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS),
|
|
209
190
|
},
|
|
210
191
|
slashingVetoer: {
|
|
211
192
|
env: 'AZTEC_SLASHING_VETOER',
|
|
212
193
|
description: 'The slashing vetoer',
|
|
213
194
|
parseEnv: (val: string) => EthAddress.fromString(val),
|
|
214
|
-
defaultValue:
|
|
195
|
+
defaultValue: EthAddress.fromString(l1ContractsDefaultEnv.AZTEC_SLASHING_VETOER),
|
|
215
196
|
},
|
|
216
197
|
slashingDisableDuration: {
|
|
217
198
|
env: 'AZTEC_SLASHING_DISABLE_DURATION',
|
|
218
199
|
description: 'How long slashing can be disabled for in seconds when vetoer disables it',
|
|
219
|
-
...numberConfigHelper(
|
|
200
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_SLASHING_DISABLE_DURATION),
|
|
220
201
|
},
|
|
221
202
|
governanceProposerQuorum: {
|
|
222
203
|
env: 'AZTEC_GOVERNANCE_PROPOSER_QUORUM',
|
|
@@ -226,26 +207,32 @@ export const l1ContractsConfigMappings: ConfigMappingsType<L1ContractsConfig> =
|
|
|
226
207
|
governanceProposerRoundSize: {
|
|
227
208
|
env: 'AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE',
|
|
228
209
|
description: 'The governance proposing round size',
|
|
229
|
-
...numberConfigHelper(
|
|
210
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE),
|
|
230
211
|
},
|
|
231
212
|
manaTarget: {
|
|
232
213
|
env: 'AZTEC_MANA_TARGET',
|
|
233
214
|
description: 'The mana target for the rollup',
|
|
234
|
-
...bigintConfigHelper(
|
|
215
|
+
...bigintConfigHelper(BigInt(l1ContractsDefaultEnv.AZTEC_MANA_TARGET)),
|
|
235
216
|
},
|
|
236
217
|
provingCostPerMana: {
|
|
237
218
|
env: 'AZTEC_PROVING_COST_PER_MANA',
|
|
238
219
|
description: 'The proving cost per mana',
|
|
239
|
-
...bigintConfigHelper(
|
|
220
|
+
...bigintConfigHelper(BigInt(l1ContractsDefaultEnv.AZTEC_PROVING_COST_PER_MANA)),
|
|
240
221
|
},
|
|
241
222
|
exitDelaySeconds: {
|
|
242
223
|
env: 'AZTEC_EXIT_DELAY_SECONDS',
|
|
243
224
|
description: 'The delay before a validator can exit the set',
|
|
244
|
-
...numberConfigHelper(
|
|
225
|
+
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_EXIT_DELAY_SECONDS),
|
|
245
226
|
},
|
|
246
227
|
...l1TxUtilsConfigMappings,
|
|
247
228
|
};
|
|
248
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Default L1 contracts configuration derived from l1ContractsConfigMappings.
|
|
232
|
+
* Source of truth: spartan/environments/defaults.yml -> defaults.l1-contracts
|
|
233
|
+
*/
|
|
234
|
+
export const DefaultL1ContractsConfig = getDefaultConfig(l1ContractsConfigMappings);
|
|
235
|
+
|
|
249
236
|
export const genesisStateConfigMappings: ConfigMappingsType<GenesisStateConfig> = {
|
|
250
237
|
testAccounts: {
|
|
251
238
|
env: 'TEST_ACCOUNTS',
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# L1 Contract Wrappers
|
|
2
|
+
|
|
3
|
+
This folder contains TypeScript wrappers for L1 contracts defined in `l1-contracts/`. These wrappers are used by the node client to interact with the rollup and related contracts on Ethereum.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
The goal of wrapping is to shield consumers from L1-specific and viem-specific details. Clients using these wrappers interact with domain types and branded types native to the Aztec codebase, without needing to understand viem's ABI type system or deal with raw types like `Hex` and `bigint`.
|
|
8
|
+
|
|
9
|
+
## Type Safety
|
|
10
|
+
|
|
11
|
+
### Explicit Return Types
|
|
12
|
+
|
|
13
|
+
Every function in the contract wrappers must declare its return type explicitly. This is critical because viem's type inference over ABI types is slow and significantly impacts IDE performance.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// Good: Explicit return type
|
|
17
|
+
async getSlotNumber(): Promise<SlotNumber> {
|
|
18
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Bad: Inferred return type (slow)
|
|
22
|
+
async getSlotNumber() {
|
|
23
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot());
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Branded and Domain Types
|
|
28
|
+
|
|
29
|
+
Use branded types and domain-specific types instead of viem's autogenerated types for both arguments and return values:
|
|
30
|
+
|
|
31
|
+
- `CheckpointNumber`, `EpochNumber`, `SlotNumber` instead of `bigint`
|
|
32
|
+
- `EthAddress` instead of `` `0x${string}` `` or `Hex`
|
|
33
|
+
- `Fr`, `Buffer32` instead of `Hex` for hashes and field elements
|
|
34
|
+
- Custom domain types (e.g., `CheckpointLog`, `AttesterView`) instead of raw tuples
|
|
35
|
+
|
|
36
|
+
Type conversions happen inside wrapper methods, not at the call site:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
async getCheckpoint(checkpointNumber: CheckpointNumber): Promise<CheckpointLog> {
|
|
40
|
+
const result = await this.rollup.read.getCheckpoint([BigInt(checkpointNumber)]);
|
|
41
|
+
return {
|
|
42
|
+
archive: Fr.fromString(result.archive),
|
|
43
|
+
headerHash: Buffer32.fromString(result.headerHash),
|
|
44
|
+
blockCount: result.blockCount,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Wrapper Pattern
|
|
50
|
+
|
|
51
|
+
### Basic Structure
|
|
52
|
+
|
|
53
|
+
Each wrapper follows a consistent structure:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
export class FooContract {
|
|
57
|
+
private readonly foo: GetContractReturnType<typeof FooAbi, ViemClient>;
|
|
58
|
+
|
|
59
|
+
constructor(
|
|
60
|
+
public readonly client: ViemClient,
|
|
61
|
+
address: Hex | EthAddress,
|
|
62
|
+
) {
|
|
63
|
+
if (address instanceof EthAddress) {
|
|
64
|
+
address = address.toString();
|
|
65
|
+
}
|
|
66
|
+
this.foo = getContract({ address, abi: FooAbi, client });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public get address(): Hex {
|
|
70
|
+
return this.foo.address;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public getContract(): GetContractReturnType<typeof FooAbi, ViemClient> {
|
|
74
|
+
return this.foo;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The raw contract is exposed via `getContract()` for cases where direct access is needed, but most consumers should use the typed wrapper methods. Relying on `getContract()` is a code smell and should be avoided.
|
|
80
|
+
|
|
81
|
+
### Static Factory Methods
|
|
82
|
+
|
|
83
|
+
Wrappers may provide static factory methods for common initialization patterns:
|
|
84
|
+
|
|
85
|
+
- `getFromConfig(config)` - construct from configuration object
|
|
86
|
+
- `getFromL1ContractsValues(deployResult)` - construct from deployment result
|
|
87
|
+
|
|
88
|
+
### Wallet Assertions
|
|
89
|
+
|
|
90
|
+
For write operations that require a wallet, use an assertion helper:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
private assertWallet(): GetContractReturnType<typeof FooAbi, ExtendedViemWalletClient> {
|
|
94
|
+
if (!isExtendedClient(this.client)) {
|
|
95
|
+
throw new Error('Wallet client is required for this operation');
|
|
96
|
+
}
|
|
97
|
+
return this.foo as GetContractReturnType<typeof FooAbi, ExtendedViemWalletClient>;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Event Handling
|
|
102
|
+
|
|
103
|
+
### Event Log Types
|
|
104
|
+
|
|
105
|
+
Event logs are wrapped in `L1EventLog<T>` to include L1 block context:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
type L1EventLog<T> = {
|
|
109
|
+
l1BlockNumber: bigint;
|
|
110
|
+
l1BlockHash: Buffer32;
|
|
111
|
+
l1TransactionHash: Hex;
|
|
112
|
+
args: T;
|
|
113
|
+
};
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Event Fetching
|
|
117
|
+
|
|
118
|
+
Methods that fetch events convert viem's raw logs to domain types:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
|
|
122
|
+
const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
|
|
123
|
+
return logs.map(log => ({
|
|
124
|
+
l1BlockNumber: log.blockNumber!,
|
|
125
|
+
l1BlockHash: Buffer32.fromString(log.blockHash!),
|
|
126
|
+
l1TransactionHash: log.transactionHash!,
|
|
127
|
+
args: {
|
|
128
|
+
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
129
|
+
// ... convert other fields
|
|
130
|
+
},
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Event Listeners
|
|
136
|
+
|
|
137
|
+
For reactive event handling, wrapper methods convert arguments before invoking callbacks:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
public listenToCheckpointInvalidated(
|
|
141
|
+
callback: (args: { checkpointNumber: CheckpointNumber }) => unknown,
|
|
142
|
+
): WatchContractEventReturnType {
|
|
143
|
+
return this.rollup.watchEvent.CheckpointInvalidated({}, {
|
|
144
|
+
onLogs: logs => {
|
|
145
|
+
for (const log of logs) {
|
|
146
|
+
if (log.args.checkpointNumber !== undefined) {
|
|
147
|
+
callback({ checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber) });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Error Handling
|
|
156
|
+
|
|
157
|
+
Custom error classes in `errors.ts` extend `Error` and set `this.name` for proper error identification. Include relevant context as public readonly properties.
|
package/src/contracts/inbox.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
4
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
5
|
import { InboxAbi } from '@aztec/l1-artifacts/InboxAbi';
|
|
4
6
|
|
|
@@ -8,8 +10,20 @@ import { getPublicClient } from '../client.js';
|
|
|
8
10
|
import type { DeployAztecL1ContractsReturnType } from '../deploy_aztec_l1_contracts.js';
|
|
9
11
|
import type { L1ReaderConfig } from '../l1_reader.js';
|
|
10
12
|
import type { ViemClient } from '../types.js';
|
|
13
|
+
import type { L1EventLog } from './log.js';
|
|
11
14
|
import { checkBlockTag } from './utils.js';
|
|
12
15
|
|
|
16
|
+
/** Arguments for the MessageSent event. */
|
|
17
|
+
export type MessageSentArgs = {
|
|
18
|
+
index: bigint;
|
|
19
|
+
leaf: Fr;
|
|
20
|
+
checkpointNumber: CheckpointNumber;
|
|
21
|
+
rollingHash: Buffer16;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** Log type for MessageSent events. */
|
|
25
|
+
export type MessageSentLog = L1EventLog<MessageSentArgs>;
|
|
26
|
+
|
|
13
27
|
export class InboxContract {
|
|
14
28
|
private readonly inbox: GetContractReturnType<typeof InboxAbi, ViemClient>;
|
|
15
29
|
|
|
@@ -59,6 +73,39 @@ export class InboxContract {
|
|
|
59
73
|
treeInProgress: state.inProgress,
|
|
60
74
|
};
|
|
61
75
|
}
|
|
76
|
+
|
|
77
|
+
/** Fetches MessageSent events within the given block range. */
|
|
78
|
+
async getMessageSentEvents(fromBlock: bigint, toBlock: bigint): Promise<MessageSentLog[]> {
|
|
79
|
+
const logs = await this.inbox.getEvents.MessageSent({}, { fromBlock, toBlock });
|
|
80
|
+
return logs
|
|
81
|
+
.filter(log => log.blockNumber! >= fromBlock && log.blockNumber! <= toBlock)
|
|
82
|
+
.map(log => this.mapMessageSentLog(log));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Fetches MessageSent events for a specific message hash within the given block range. */
|
|
86
|
+
async getMessageSentEventByHash(hash: Hex, fromBlock: bigint, toBlock: bigint): Promise<MessageSentLog[]> {
|
|
87
|
+
const logs = await this.inbox.getEvents.MessageSent({ hash }, { fromBlock, toBlock });
|
|
88
|
+
return logs.map(log => this.mapMessageSentLog(log));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private mapMessageSentLog(log: {
|
|
92
|
+
blockNumber: bigint | null;
|
|
93
|
+
blockHash: `0x${string}` | null;
|
|
94
|
+
transactionHash: `0x${string}` | null;
|
|
95
|
+
args: { index?: bigint; hash?: `0x${string}`; checkpointNumber?: bigint; rollingHash?: `0x${string}` };
|
|
96
|
+
}): MessageSentLog {
|
|
97
|
+
return {
|
|
98
|
+
l1BlockNumber: log.blockNumber!,
|
|
99
|
+
l1BlockHash: Buffer32.fromString(log.blockHash!),
|
|
100
|
+
l1TransactionHash: log.transactionHash!,
|
|
101
|
+
args: {
|
|
102
|
+
index: log.args.index!,
|
|
103
|
+
leaf: Fr.fromString(log.args.hash!),
|
|
104
|
+
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
105
|
+
rollingHash: Buffer16.fromString(log.args.rollingHash!),
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
62
109
|
}
|
|
63
110
|
|
|
64
111
|
export type InboxContractState = {
|
package/src/contracts/index.ts
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Buffer32 } from '@aztec/foundation/buffer';
|
|
2
|
+
|
|
3
|
+
/** Base L1 event log with common fields. */
|
|
4
|
+
export type L1EventLog<T> = {
|
|
5
|
+
/** L1 block number where the event was emitted. */
|
|
6
|
+
l1BlockNumber: bigint;
|
|
7
|
+
/** L1 block hash. */
|
|
8
|
+
l1BlockHash: Buffer32;
|
|
9
|
+
/** L1 transaction hash that emitted the event. */
|
|
10
|
+
l1TransactionHash: `0x${string}`;
|
|
11
|
+
/** Event-specific arguments. */
|
|
12
|
+
args: T;
|
|
13
|
+
};
|
package/src/contracts/rollup.ts
CHANGED
|
@@ -30,6 +30,7 @@ import type { ViemClient } from '../types.js';
|
|
|
30
30
|
import { formatViemError } from '../utils.js';
|
|
31
31
|
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
32
32
|
import { GSEContract } from './gse.js';
|
|
33
|
+
import type { L1EventLog } from './log.js';
|
|
33
34
|
import { SlasherContract } from './slasher_contract.js';
|
|
34
35
|
import { TallySlashingProposerContract } from './tally_slashing_proposer.js';
|
|
35
36
|
import { checkBlockTag } from './utils.js';
|
|
@@ -69,6 +70,7 @@ export type ViemHeader = {
|
|
|
69
70
|
blockHeadersHash: `0x${string}`;
|
|
70
71
|
blobsHash: `0x${string}`;
|
|
71
72
|
inHash: `0x${string}`;
|
|
73
|
+
outHash: `0x${string}`;
|
|
72
74
|
slotNumber: bigint;
|
|
73
75
|
timestamp: bigint;
|
|
74
76
|
coinbase: `0x${string}`;
|
|
@@ -185,6 +187,20 @@ export type RollupStatusResponse = {
|
|
|
185
187
|
archiveOfMyCheckpoint: Fr;
|
|
186
188
|
};
|
|
187
189
|
|
|
190
|
+
/** Arguments for the CheckpointProposed event. */
|
|
191
|
+
export type CheckpointProposedArgs = {
|
|
192
|
+
checkpointNumber: CheckpointNumber;
|
|
193
|
+
archive: Fr;
|
|
194
|
+
versionedBlobHashes: Buffer[];
|
|
195
|
+
/** Hash of attestations. Undefined for older events (backwards compatibility). */
|
|
196
|
+
attestationsHash?: Buffer32;
|
|
197
|
+
/** Digest of the payload. Undefined for older events (backwards compatibility). */
|
|
198
|
+
payloadDigest?: Buffer32;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/** Log type for CheckpointProposed events. */
|
|
202
|
+
export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
203
|
+
|
|
188
204
|
export class RollupContract {
|
|
189
205
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
190
206
|
|
|
@@ -965,4 +981,23 @@ export class RollupContract {
|
|
|
965
981
|
},
|
|
966
982
|
);
|
|
967
983
|
}
|
|
984
|
+
|
|
985
|
+
/** Fetches CheckpointProposed events within the given block range. */
|
|
986
|
+
async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
|
|
987
|
+
const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
|
|
988
|
+
return logs
|
|
989
|
+
.filter(log => log.blockNumber! >= fromBlock && log.blockNumber! <= toBlock)
|
|
990
|
+
.map(log => ({
|
|
991
|
+
l1BlockNumber: log.blockNumber!,
|
|
992
|
+
l1BlockHash: Buffer32.fromString(log.blockHash!),
|
|
993
|
+
l1TransactionHash: log.transactionHash!,
|
|
994
|
+
args: {
|
|
995
|
+
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
996
|
+
archive: Fr.fromString(log.args.archive!),
|
|
997
|
+
versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
|
|
998
|
+
attestationsHash: log.args.attestationsHash ? Buffer32.fromString(log.args.attestationsHash) : undefined,
|
|
999
|
+
payloadDigest: log.args.payloadDigest ? Buffer32.fromString(log.args.payloadDigest) : undefined,
|
|
1000
|
+
},
|
|
1001
|
+
}));
|
|
1002
|
+
}
|
|
968
1003
|
}
|
|
@@ -10,7 +10,9 @@ import { fileURLToPath } from '@aztec/foundation/url';
|
|
|
10
10
|
import { bn254 } from '@noble/curves/bn254';
|
|
11
11
|
import type { Abi, Narrow } from 'abitype';
|
|
12
12
|
import { spawn } from 'child_process';
|
|
13
|
-
import {
|
|
13
|
+
import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, rmSync } from 'fs';
|
|
14
|
+
import { tmpdir } from 'os';
|
|
15
|
+
import { dirname, join, resolve } from 'path';
|
|
14
16
|
import readline from 'readline';
|
|
15
17
|
import type { Hex } from 'viem';
|
|
16
18
|
import { foundry, mainnet, sepolia } from 'viem/chains';
|
|
@@ -107,17 +109,66 @@ export interface ValidatorJson {
|
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
/**
|
|
110
|
-
* Gets the path to the l1-contracts directory.
|
|
112
|
+
* Gets the path to the l1-contracts foundry artifacts directory.
|
|
113
|
+
* These are copied from l1-contracts to yarn-project/l1-artifacts/l1-contracts
|
|
114
|
+
* during build to make yarn-project self-contained.
|
|
111
115
|
*/
|
|
112
116
|
export function getL1ContractsPath(): string {
|
|
113
|
-
// Try to find l1-contracts relative to this file
|
|
114
117
|
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const l1ContractsPath = resolve(currentDir, '..', '..', '..', 'l1-contracts');
|
|
118
|
+
// Go up from yarn-project/ethereum/dest to yarn-project, then to l1-artifacts/l1-contracts
|
|
119
|
+
const l1ContractsPath = resolve(currentDir, '..', '..', 'l1-artifacts', 'l1-contracts');
|
|
118
120
|
return l1ContractsPath;
|
|
119
121
|
}
|
|
120
122
|
|
|
123
|
+
// Cached deployment directory
|
|
124
|
+
let preparedDeployDir: string | undefined;
|
|
125
|
+
|
|
126
|
+
function cleanupDeployDir() {
|
|
127
|
+
if (preparedDeployDir) {
|
|
128
|
+
try {
|
|
129
|
+
rmSync(preparedDeployDir, { recursive: true, force: true });
|
|
130
|
+
} catch {
|
|
131
|
+
// ignore cleanup errors
|
|
132
|
+
}
|
|
133
|
+
preparedDeployDir = undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Prepares a temp directory for forge deployment.
|
|
139
|
+
* Copies all artifacts with preserved timestamps (required for forge cache validity).
|
|
140
|
+
* A fresh broadcast/ directory is created for deployment outputs.
|
|
141
|
+
*/
|
|
142
|
+
export function prepareL1ContractsForDeployment(): string {
|
|
143
|
+
if (preparedDeployDir && existsSync(preparedDeployDir)) {
|
|
144
|
+
return preparedDeployDir;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const basePath = getL1ContractsPath();
|
|
148
|
+
const tempDir = mkdtempSync(join(tmpdir(), '.foundry-deploy-'));
|
|
149
|
+
preparedDeployDir = tempDir;
|
|
150
|
+
process.on('exit', cleanupDeployDir);
|
|
151
|
+
|
|
152
|
+
// Copy all dirs with preserved timestamps (required for forge cache validity)
|
|
153
|
+
const copyOpts = { recursive: true, preserveTimestamps: true };
|
|
154
|
+
cpSync(join(basePath, 'out'), join(tempDir, 'out'), copyOpts);
|
|
155
|
+
cpSync(join(basePath, 'lib'), join(tempDir, 'lib'), copyOpts);
|
|
156
|
+
cpSync(join(basePath, 'cache'), join(tempDir, 'cache'), copyOpts);
|
|
157
|
+
cpSync(join(basePath, 'src'), join(tempDir, 'src'), copyOpts);
|
|
158
|
+
cpSync(join(basePath, 'script'), join(tempDir, 'script'), copyOpts);
|
|
159
|
+
cpSync(join(basePath, 'generated'), join(tempDir, 'generated'), copyOpts);
|
|
160
|
+
cpSync(join(basePath, 'foundry.toml'), join(tempDir, 'foundry.toml'));
|
|
161
|
+
cpSync(join(basePath, 'foundry.lock'), join(tempDir, 'foundry.lock'));
|
|
162
|
+
for (const file of readdirSync(basePath)) {
|
|
163
|
+
if (file.startsWith('solc-')) {
|
|
164
|
+
cpSync(join(basePath, file), join(tempDir, file));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
mkdirSync(join(tempDir, 'broadcast'));
|
|
169
|
+
return tempDir;
|
|
170
|
+
}
|
|
171
|
+
|
|
121
172
|
/**
|
|
122
173
|
* Computes the validator data for passing to Solidity.
|
|
123
174
|
* Only computes the G2 public key (which requires scalar multiplication on G2, not available in EVM).
|
|
@@ -211,7 +262,6 @@ export async function deployAztecL1Contracts(
|
|
|
211
262
|
'Initial validator funding requires minting tokens, which is not possible with an external token.',
|
|
212
263
|
);
|
|
213
264
|
}
|
|
214
|
-
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
215
265
|
const chain = createEthereumChain([rpcUrl], chainId);
|
|
216
266
|
|
|
217
267
|
const l1Client = createExtendedL1Client([rpcUrl], privateKey, chain.chainInfo);
|
|
@@ -240,8 +290,8 @@ export async function deployAztecL1Contracts(
|
|
|
240
290
|
}
|
|
241
291
|
}
|
|
242
292
|
|
|
243
|
-
//
|
|
244
|
-
const l1ContractsPath =
|
|
293
|
+
// Use foundry-artifacts from l1-artifacts package
|
|
294
|
+
const l1ContractsPath = prepareL1ContractsForDeployment();
|
|
245
295
|
|
|
246
296
|
const FORGE_SCRIPT = 'script/deploy/DeployAztecL1Contracts.s.sol';
|
|
247
297
|
await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
@@ -258,7 +308,7 @@ export async function deployAztecL1Contracts(
|
|
|
258
308
|
}
|
|
259
309
|
|
|
260
310
|
// From heuristic testing. More caused issues with anvil.
|
|
261
|
-
const MAGIC_ANVIL_BATCH_SIZE =
|
|
311
|
+
const MAGIC_ANVIL_BATCH_SIZE = 8;
|
|
262
312
|
// Anvil seems to stall with unbounded batch size. Otherwise no max batch size is desirable.
|
|
263
313
|
const forgeArgs = [
|
|
264
314
|
'script',
|
|
@@ -481,6 +531,7 @@ export function getDeployRollupForUpgradeEnvVars(
|
|
|
481
531
|
AZTEC_PROOF_SUBMISSION_EPOCHS: args.aztecProofSubmissionEpochs.toString(),
|
|
482
532
|
AZTEC_LOCAL_EJECTION_THRESHOLD: args.localEjectionThreshold.toString(),
|
|
483
533
|
AZTEC_SLASHING_LIFETIME_IN_ROUNDS: args.slashingLifetimeInRounds.toString(),
|
|
534
|
+
AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS: args.slashingExecutionDelayInRounds.toString(),
|
|
484
535
|
AZTEC_SLASHING_VETOER: args.slashingVetoer.toString(),
|
|
485
536
|
AZTEC_SLASHING_DISABLE_DURATION: args.slashingDisableDuration.toString(),
|
|
486
537
|
AZTEC_MANA_TARGET: args.manaTarget.toString(),
|
|
@@ -513,10 +564,8 @@ export const deployRollupForUpgrade = async (
|
|
|
513
564
|
| 'zkPassportArgs'
|
|
514
565
|
>,
|
|
515
566
|
) => {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
// Relative location of l1-contracts in monorepo or docker image.
|
|
519
|
-
const l1ContractsPath = resolve(currentDir, '..', '..', '..', 'l1-contracts');
|
|
567
|
+
// Use foundry-artifacts from l1-artifacts package
|
|
568
|
+
const l1ContractsPath = prepareL1ContractsForDeployment();
|
|
520
569
|
|
|
521
570
|
const FORGE_SCRIPT = 'script/deploy/DeployRollupForUpgrade.s.sol';
|
|
522
571
|
await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
|