@aztec/ethereum 0.87.2 → 0.87.3-nightly.20250528
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.js +3 -3
- package/dest/contracts/governance.d.ts +1 -1
- package/dest/contracts/rollup.d.ts +25 -8
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +26 -6
- package/dest/contracts/slashing_proposer.d.ts +17 -2
- package/dest/contracts/slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/slashing_proposer.js +84 -3
- package/dest/deploy_l1_contracts.d.ts +3538 -284
- package/dest/deploy_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_l1_contracts.js +85 -22
- package/dest/l1_contract_addresses.d.ts +5 -1
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +2 -1
- package/dest/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils.js +11 -2
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +152 -152
- package/package.json +4 -4
- package/src/config.ts +3 -3
- package/src/contracts/rollup.ts +33 -6
- package/src/contracts/slashing_proposer.ts +113 -3
- package/src/deploy_l1_contracts.ts +112 -33
- package/src/l1_contract_addresses.ts +3 -1
- package/src/l1_tx_utils.ts +6 -2
- package/src/utils.ts +173 -172
package/dest/utils.js
CHANGED
|
@@ -109,25 +109,6 @@ function getNestedErrorData(error) {
|
|
|
109
109
|
// Create a clone to avoid modifying the original
|
|
110
110
|
const errorClone = structuredClone(error);
|
|
111
111
|
// Helper function to recursively remove ABI properties
|
|
112
|
-
const stripAbis = (obj)=>{
|
|
113
|
-
if (!obj || typeof obj !== 'object') {
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
// Delete ABI property at current level
|
|
117
|
-
if ('abi' in obj) {
|
|
118
|
-
delete obj.abi;
|
|
119
|
-
}
|
|
120
|
-
// Process cause property
|
|
121
|
-
if (obj.cause) {
|
|
122
|
-
stripAbis(obj.cause);
|
|
123
|
-
}
|
|
124
|
-
// Process arrays and objects
|
|
125
|
-
Object.values(obj).forEach((value)=>{
|
|
126
|
-
if (value && typeof value === 'object') {
|
|
127
|
-
stripAbis(value);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
};
|
|
131
112
|
// Strip ABIs from the clone
|
|
132
113
|
stripAbis(errorClone);
|
|
133
114
|
// Use the cleaned clone for further processing
|
|
@@ -137,139 +118,6 @@ function getNestedErrorData(error) {
|
|
|
137
118
|
if (error instanceof Error) {
|
|
138
119
|
return new FormattedViemError(error.message, error?.metaMessages);
|
|
139
120
|
}
|
|
140
|
-
const truncateHex = (hex, length = 100)=>{
|
|
141
|
-
if (!hex || typeof hex !== 'string') {
|
|
142
|
-
return hex;
|
|
143
|
-
}
|
|
144
|
-
if (!hex.startsWith('0x')) {
|
|
145
|
-
return hex;
|
|
146
|
-
}
|
|
147
|
-
if (hex.length <= length * 2) {
|
|
148
|
-
return hex;
|
|
149
|
-
}
|
|
150
|
-
// For extremely large hex strings, use more aggressive truncation
|
|
151
|
-
if (hex.length > 10000) {
|
|
152
|
-
return `${hex.slice(0, length)}...<${hex.length - length * 2} chars omitted>...${hex.slice(-length)}`;
|
|
153
|
-
}
|
|
154
|
-
return `${hex.slice(0, length)}...${hex.slice(-length)}`;
|
|
155
|
-
};
|
|
156
|
-
const replaceHexStrings = (text, options = {})=>{
|
|
157
|
-
const { minLength = 10, maxLength = Infinity, truncateLength = 100, pattern, transform = (hex)=>truncateHex(hex, truncateLength) } = options;
|
|
158
|
-
const hexRegex = pattern ?? new RegExp(`(0x[a-fA-F0-9]{${minLength},${maxLength}})`, 'g');
|
|
159
|
-
return text.replace(hexRegex, (match)=>transform(match));
|
|
160
|
-
};
|
|
161
|
-
const formatRequestBody = (body)=>{
|
|
162
|
-
try {
|
|
163
|
-
// Special handling for eth_sendRawTransaction
|
|
164
|
-
if (body.includes('"method":"eth_sendRawTransaction"')) {
|
|
165
|
-
try {
|
|
166
|
-
const parsed = JSON.parse(body);
|
|
167
|
-
if (parsed.params && Array.isArray(parsed.params) && parsed.params.length > 0) {
|
|
168
|
-
// These are likely large transaction hex strings
|
|
169
|
-
parsed.params = parsed.params.map((param)=>{
|
|
170
|
-
if (typeof param === 'string' && param.startsWith('0x') && param.length > 1000) {
|
|
171
|
-
return truncateHex(param, 200);
|
|
172
|
-
}
|
|
173
|
-
return param;
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
return JSON.stringify(parsed, null, 2);
|
|
177
|
-
} catch {
|
|
178
|
-
// If specific parsing fails, fall back to regex-based truncation
|
|
179
|
-
return replaceHexStrings(body, {
|
|
180
|
-
pattern: /"params":\s*\[\s*"(0x[a-fA-F0-9]{1000,})"\s*\]/g,
|
|
181
|
-
transform: (hex)=>`"params":["${truncateHex(hex, 200)}"]`
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
// For extremely large request bodies, use simple truncation instead of parsing
|
|
186
|
-
if (body.length > 50000) {
|
|
187
|
-
const jsonStart = body.indexOf('{');
|
|
188
|
-
const jsonEnd = body.lastIndexOf('}');
|
|
189
|
-
if (jsonStart >= 0 && jsonEnd > jsonStart) {
|
|
190
|
-
return replaceHexStrings(body, {
|
|
191
|
-
minLength: 10000,
|
|
192
|
-
truncateLength: 200
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
const parsed = JSON.parse(body);
|
|
197
|
-
// Recursively process all parameters that might contain hex strings
|
|
198
|
-
const processParams = (obj)=>{
|
|
199
|
-
if (Array.isArray(obj)) {
|
|
200
|
-
return obj.map((item)=>processParams(item));
|
|
201
|
-
}
|
|
202
|
-
if (typeof obj === 'object' && obj !== null) {
|
|
203
|
-
const result = {};
|
|
204
|
-
for (const [key, value] of Object.entries(obj)){
|
|
205
|
-
result[key] = processParams(value);
|
|
206
|
-
}
|
|
207
|
-
return result;
|
|
208
|
-
}
|
|
209
|
-
if (typeof obj === 'string') {
|
|
210
|
-
if (obj.startsWith('0x')) {
|
|
211
|
-
return truncateHex(obj);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
return obj;
|
|
215
|
-
};
|
|
216
|
-
// Process the entire request body
|
|
217
|
-
const processed = processParams(parsed);
|
|
218
|
-
return JSON.stringify(processed, null, 2);
|
|
219
|
-
} catch {
|
|
220
|
-
// If JSON parsing fails, do a simple truncation of any large hex strings
|
|
221
|
-
return replaceHexStrings(body, {
|
|
222
|
-
minLength: 1000,
|
|
223
|
-
truncateLength: 150
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
const extractAndFormatRequestBody = (message)=>{
|
|
228
|
-
// First check if message is extremely large and contains very large hex strings
|
|
229
|
-
if (message.length > 50000) {
|
|
230
|
-
message = replaceHexStrings(message, {
|
|
231
|
-
minLength: 10000,
|
|
232
|
-
truncateLength: 200
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
// Add a specific check for RPC calls with large params
|
|
236
|
-
if (message.includes('"method":"eth_sendRawTransaction"')) {
|
|
237
|
-
message = replaceHexStrings(message, {
|
|
238
|
-
pattern: /"params":\s*\[\s*"(0x[a-fA-F0-9]{1000,})"\s*\]/g,
|
|
239
|
-
transform: (hex)=>`"params":["${truncateHex(hex, 200)}"]`
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
// First handle Request body JSON
|
|
243
|
-
const requestBodyRegex = /Request body: ({[\s\S]*?})\n/g;
|
|
244
|
-
let result = message.replace(requestBodyRegex, (match, body)=>{
|
|
245
|
-
return `Request body: ${formatRequestBody(body)}\n`;
|
|
246
|
-
});
|
|
247
|
-
// Then handle Arguments section
|
|
248
|
-
const argsRegex = /((?:Request |Estimate Gas )?Arguments:[\s\S]*?(?=\n\n|$))/g;
|
|
249
|
-
result = result.replace(argsRegex, (section)=>{
|
|
250
|
-
const lines = section.split('\n');
|
|
251
|
-
const processedLines = lines.map((line)=>{
|
|
252
|
-
// Check if line contains a colon followed by content
|
|
253
|
-
const colonIndex = line.indexOf(':');
|
|
254
|
-
if (colonIndex !== -1) {
|
|
255
|
-
const [prefix, content] = [
|
|
256
|
-
line.slice(0, colonIndex + 1),
|
|
257
|
-
line.slice(colonIndex + 1).trim()
|
|
258
|
-
];
|
|
259
|
-
// If content contains a hex string, truncate it
|
|
260
|
-
if (content.includes('0x')) {
|
|
261
|
-
const processedContent = replaceHexStrings(content);
|
|
262
|
-
return `${prefix} ${processedContent}`;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
return line;
|
|
266
|
-
});
|
|
267
|
-
return processedLines.join('\n');
|
|
268
|
-
});
|
|
269
|
-
// Finally, catch any remaining hex strings in the message
|
|
270
|
-
result = replaceHexStrings(result);
|
|
271
|
-
return result;
|
|
272
|
-
};
|
|
273
121
|
// Extract the actual error message and highlight it for clarity
|
|
274
122
|
let formattedRes = extractAndFormatRequestBody(error?.message || String(error));
|
|
275
123
|
let errorDetail = '';
|
|
@@ -299,6 +147,158 @@ function getNestedErrorData(error) {
|
|
|
299
147
|
}
|
|
300
148
|
return new FormattedViemError(formattedRes.replace(/\\n/g, '\n'), error?.metaMessages);
|
|
301
149
|
}
|
|
150
|
+
function stripAbis(obj) {
|
|
151
|
+
if (!obj || typeof obj !== 'object') {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// Delete ABI property at current level
|
|
155
|
+
if ('abi' in obj) {
|
|
156
|
+
delete obj.abi;
|
|
157
|
+
}
|
|
158
|
+
// Process cause property
|
|
159
|
+
if (obj.cause) {
|
|
160
|
+
stripAbis(obj.cause);
|
|
161
|
+
}
|
|
162
|
+
// Process arrays and objects
|
|
163
|
+
Object.values(obj).forEach((value)=>{
|
|
164
|
+
if (value && typeof value === 'object') {
|
|
165
|
+
stripAbis(value);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function extractAndFormatRequestBody(message) {
|
|
170
|
+
// First check if message is extremely large and contains very large hex strings
|
|
171
|
+
if (message.length > 50000) {
|
|
172
|
+
message = replaceHexStrings(message, {
|
|
173
|
+
minLength: 10000,
|
|
174
|
+
truncateLength: 200
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// Add a specific check for RPC calls with large params
|
|
178
|
+
if (message.includes('"method":"eth_sendRawTransaction"')) {
|
|
179
|
+
message = replaceHexStrings(message, {
|
|
180
|
+
pattern: /"params":\s*\[\s*"(0x[a-fA-F0-9]{1000,})"\s*\]/g,
|
|
181
|
+
transform: (hex)=>`"params":["${truncateHex(hex, 200)}"]`
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
// First handle Request body JSON
|
|
185
|
+
const requestBodyRegex = /Request body: ({[\s\S]*?})\n/g;
|
|
186
|
+
let result = message.replace(requestBodyRegex, (match, body)=>{
|
|
187
|
+
return `Request body: ${formatRequestBody(body)}\n`;
|
|
188
|
+
});
|
|
189
|
+
// Then handle Arguments section
|
|
190
|
+
const argsRegex = /((?:Request |Estimate Gas )?Arguments:[\s\S]*?(?=\n\n|$))/g;
|
|
191
|
+
result = result.replace(argsRegex, (section)=>{
|
|
192
|
+
const lines = section.split('\n');
|
|
193
|
+
const processedLines = lines.map((line)=>{
|
|
194
|
+
// Check if line contains a colon followed by content
|
|
195
|
+
const colonIndex = line.indexOf(':');
|
|
196
|
+
if (colonIndex !== -1) {
|
|
197
|
+
const [prefix, content] = [
|
|
198
|
+
line.slice(0, colonIndex + 1),
|
|
199
|
+
line.slice(colonIndex + 1).trim()
|
|
200
|
+
];
|
|
201
|
+
// If content contains a hex string, truncate it
|
|
202
|
+
if (content.includes('0x')) {
|
|
203
|
+
const processedContent = replaceHexStrings(content);
|
|
204
|
+
return `${prefix} ${processedContent}`;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return line;
|
|
208
|
+
});
|
|
209
|
+
return processedLines.join('\n');
|
|
210
|
+
});
|
|
211
|
+
// Finally, catch any remaining hex strings in the message
|
|
212
|
+
result = replaceHexStrings(result);
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
function truncateHex(hex, length = 100) {
|
|
216
|
+
if (!hex || typeof hex !== 'string') {
|
|
217
|
+
return hex;
|
|
218
|
+
}
|
|
219
|
+
if (!hex.startsWith('0x')) {
|
|
220
|
+
return hex;
|
|
221
|
+
}
|
|
222
|
+
if (hex.length <= length * 2) {
|
|
223
|
+
return hex;
|
|
224
|
+
}
|
|
225
|
+
// For extremely large hex strings, use more aggressive truncation
|
|
226
|
+
if (hex.length > 10000) {
|
|
227
|
+
return `${hex.slice(0, length)}...<${hex.length - length * 2} chars omitted>...${hex.slice(-length)}`;
|
|
228
|
+
}
|
|
229
|
+
return `${hex.slice(0, length)}...${hex.slice(-length)}`;
|
|
230
|
+
}
|
|
231
|
+
function replaceHexStrings(text, options = {}) {
|
|
232
|
+
const { minLength = 10, maxLength = Infinity, truncateLength = 100, pattern, transform = (hex)=>truncateHex(hex, truncateLength) } = options;
|
|
233
|
+
const hexRegex = pattern ?? new RegExp(`(0x[a-fA-F0-9]{${minLength},${maxLength}})`, 'g');
|
|
234
|
+
return text.replace(hexRegex, (match)=>transform(match));
|
|
235
|
+
}
|
|
236
|
+
function formatRequestBody(body) {
|
|
237
|
+
try {
|
|
238
|
+
// Special handling for eth_sendRawTransaction
|
|
239
|
+
if (body.includes('"method":"eth_sendRawTransaction"')) {
|
|
240
|
+
try {
|
|
241
|
+
const parsed = JSON.parse(body);
|
|
242
|
+
if (parsed.params && Array.isArray(parsed.params) && parsed.params.length > 0) {
|
|
243
|
+
// These are likely large transaction hex strings
|
|
244
|
+
parsed.params = parsed.params.map((param)=>{
|
|
245
|
+
if (typeof param === 'string' && param.startsWith('0x') && param.length > 1000) {
|
|
246
|
+
return truncateHex(param, 200);
|
|
247
|
+
}
|
|
248
|
+
return param;
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
return JSON.stringify(parsed, null, 2);
|
|
252
|
+
} catch {
|
|
253
|
+
// If specific parsing fails, fall back to regex-based truncation
|
|
254
|
+
return replaceHexStrings(body, {
|
|
255
|
+
pattern: /"params":\s*\[\s*"(0x[a-fA-F0-9]{1000,})"\s*\]/g,
|
|
256
|
+
transform: (hex)=>`"params":["${truncateHex(hex, 200)}"]`
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// For extremely large request bodies, use simple truncation instead of parsing
|
|
261
|
+
if (body.length > 50000) {
|
|
262
|
+
const jsonStart = body.indexOf('{');
|
|
263
|
+
const jsonEnd = body.lastIndexOf('}');
|
|
264
|
+
if (jsonStart >= 0 && jsonEnd > jsonStart) {
|
|
265
|
+
return replaceHexStrings(body, {
|
|
266
|
+
minLength: 10000,
|
|
267
|
+
truncateLength: 200
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const parsed = JSON.parse(body);
|
|
272
|
+
// Process the entire request body
|
|
273
|
+
const processed = processParams(parsed);
|
|
274
|
+
return JSON.stringify(processed, null, 2);
|
|
275
|
+
} catch {
|
|
276
|
+
// If JSON parsing fails, do a simple truncation of any large hex strings
|
|
277
|
+
return replaceHexStrings(body, {
|
|
278
|
+
minLength: 1000,
|
|
279
|
+
truncateLength: 150
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Recursively process all parameters that might contain hex strings
|
|
284
|
+
function processParams(obj) {
|
|
285
|
+
if (Array.isArray(obj)) {
|
|
286
|
+
return obj.map((item)=>processParams(item));
|
|
287
|
+
}
|
|
288
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
289
|
+
const result = {};
|
|
290
|
+
for (const [key, value] of Object.entries(obj)){
|
|
291
|
+
result[key] = processParams(value);
|
|
292
|
+
}
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
295
|
+
if (typeof obj === 'string') {
|
|
296
|
+
if (obj.startsWith('0x')) {
|
|
297
|
+
return truncateHex(obj);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return obj;
|
|
301
|
+
}
|
|
302
302
|
export function tryGetCustomErrorName(err) {
|
|
303
303
|
try {
|
|
304
304
|
// See https://viem.sh/docs/contract/simulateContract#handling-custom-errors
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/ethereum",
|
|
3
|
-
"version": "0.87.
|
|
3
|
+
"version": "0.87.3-nightly.20250528",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"../package.common.json"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@aztec/blob-lib": "0.87.
|
|
36
|
-
"@aztec/foundation": "0.87.
|
|
37
|
-
"@aztec/l1-artifacts": "0.87.
|
|
35
|
+
"@aztec/blob-lib": "0.87.3-nightly.20250528",
|
|
36
|
+
"@aztec/foundation": "0.87.3-nightly.20250528",
|
|
37
|
+
"@aztec/l1-artifacts": "0.87.3-nightly.20250528",
|
|
38
38
|
"@viem/anvil": "^0.0.10",
|
|
39
39
|
"dotenv": "^16.0.3",
|
|
40
40
|
"tslib": "^2.4.0",
|
package/src/config.ts
CHANGED
|
@@ -44,10 +44,10 @@ export type L1ContractsConfig = {
|
|
|
44
44
|
|
|
45
45
|
export const DefaultL1ContractsConfig = {
|
|
46
46
|
ethereumSlotDuration: 12,
|
|
47
|
-
aztecSlotDuration:
|
|
48
|
-
aztecEpochDuration:
|
|
47
|
+
aztecSlotDuration: 36,
|
|
48
|
+
aztecEpochDuration: 32,
|
|
49
49
|
aztecTargetCommitteeSize: 48,
|
|
50
|
-
aztecProofSubmissionWindow:
|
|
50
|
+
aztecProofSubmissionWindow: 64, // you have a full epoch to submit a proof after the epoch to prove ends
|
|
51
51
|
minimumStake: BigInt(100e18),
|
|
52
52
|
slashingQuorum: 6,
|
|
53
53
|
slashingRoundSize: 10,
|
package/src/contracts/rollup.ts
CHANGED
|
@@ -5,17 +5,23 @@ import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
|
5
5
|
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
6
6
|
import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
|
|
7
7
|
|
|
8
|
-
import { type Account, type GetContractReturnType, type Hex, getAddress, getContract } from 'viem';
|
|
8
|
+
import { type Account, type GetContractReturnType, type Hex, encodeFunctionData, getAddress, getContract } from 'viem';
|
|
9
9
|
|
|
10
10
|
import { getPublicClient } from '../client.js';
|
|
11
11
|
import type { DeployL1ContractsReturnType } from '../deploy_l1_contracts.js';
|
|
12
12
|
import type { L1ContractAddresses } from '../l1_contract_addresses.js';
|
|
13
13
|
import type { L1ReaderConfig } from '../l1_reader.js';
|
|
14
|
+
import type { L1TxUtils } from '../l1_tx_utils.js';
|
|
14
15
|
import type { ViemClient } from '../types.js';
|
|
15
16
|
import { formatViemError } from '../utils.js';
|
|
16
17
|
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
17
18
|
import { checkBlockTag } from './utils.js';
|
|
18
19
|
|
|
20
|
+
export type ViemCommitteeAttestation = {
|
|
21
|
+
addr: `0x${string}`;
|
|
22
|
+
signature: ViemSignature;
|
|
23
|
+
};
|
|
24
|
+
|
|
19
25
|
export type L1RollupContractAddresses = Pick<
|
|
20
26
|
L1ContractAddresses,
|
|
21
27
|
| 'rollupAddress'
|
|
@@ -26,13 +32,12 @@ export type L1RollupContractAddresses = Pick<
|
|
|
26
32
|
| 'stakingAssetAddress'
|
|
27
33
|
| 'rewardDistributorAddress'
|
|
28
34
|
| 'slashFactoryAddress'
|
|
35
|
+
| 'gseAddress'
|
|
29
36
|
>;
|
|
30
37
|
|
|
31
38
|
export type EpochProofPublicInputArgs = {
|
|
32
39
|
previousArchive: `0x${string}`;
|
|
33
40
|
endArchive: `0x${string}`;
|
|
34
|
-
endTimestamp: bigint;
|
|
35
|
-
outHash: `0x${string}`;
|
|
36
41
|
proverId: `0x${string}`;
|
|
37
42
|
};
|
|
38
43
|
|
|
@@ -279,6 +284,7 @@ export class RollupContract {
|
|
|
279
284
|
rewardDistributorAddress,
|
|
280
285
|
feeJuiceAddress,
|
|
281
286
|
stakingAssetAddress,
|
|
287
|
+
gseAddress,
|
|
282
288
|
] = (
|
|
283
289
|
await Promise.all([
|
|
284
290
|
this.rollup.read.getInbox(),
|
|
@@ -287,6 +293,7 @@ export class RollupContract {
|
|
|
287
293
|
this.rollup.read.getRewardDistributor(),
|
|
288
294
|
this.rollup.read.getFeeAsset(),
|
|
289
295
|
this.rollup.read.getStakingAsset(),
|
|
296
|
+
this.rollup.read.getGSE(),
|
|
290
297
|
] as const)
|
|
291
298
|
).map(EthAddress.fromString);
|
|
292
299
|
|
|
@@ -298,6 +305,7 @@ export class RollupContract {
|
|
|
298
305
|
feeJuiceAddress,
|
|
299
306
|
stakingAssetAddress,
|
|
300
307
|
rewardDistributorAddress,
|
|
308
|
+
gseAddress,
|
|
301
309
|
};
|
|
302
310
|
}
|
|
303
311
|
|
|
@@ -318,7 +326,7 @@ export class RollupContract {
|
|
|
318
326
|
public async validateHeader(
|
|
319
327
|
args: readonly [
|
|
320
328
|
`0x${string}`,
|
|
321
|
-
|
|
329
|
+
ViemCommitteeAttestation[],
|
|
322
330
|
`0x${string}`,
|
|
323
331
|
bigint,
|
|
324
332
|
`0x${string}`,
|
|
@@ -360,6 +368,7 @@ export class RollupContract {
|
|
|
360
368
|
slotDuration = BigInt(slotDuration);
|
|
361
369
|
}
|
|
362
370
|
const timeOfNextL1Slot = (await this.client.getBlock()).timestamp + slotDuration;
|
|
371
|
+
|
|
363
372
|
try {
|
|
364
373
|
const {
|
|
365
374
|
result: [slot, blockNumber],
|
|
@@ -429,11 +438,18 @@ export class RollupContract {
|
|
|
429
438
|
return this.rollup.read.getAttesters();
|
|
430
439
|
}
|
|
431
440
|
|
|
432
|
-
|
|
441
|
+
getAttesterView(address: Hex | EthAddress) {
|
|
442
|
+
if (address instanceof EthAddress) {
|
|
443
|
+
address = address.toString();
|
|
444
|
+
}
|
|
445
|
+
return this.rollup.read.getAttesterView([address]);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
getStatus(address: Hex | EthAddress) {
|
|
433
449
|
if (address instanceof EthAddress) {
|
|
434
450
|
address = address.toString();
|
|
435
451
|
}
|
|
436
|
-
return this.rollup.read.
|
|
452
|
+
return this.rollup.read.getStatus([address]);
|
|
437
453
|
}
|
|
438
454
|
|
|
439
455
|
getBlobPublicInputsHash(blockNumber: bigint) {
|
|
@@ -450,4 +466,15 @@ export class RollupContract {
|
|
|
450
466
|
}
|
|
451
467
|
return this.rollup.read.getProposerForAttester([attester]);
|
|
452
468
|
}
|
|
469
|
+
|
|
470
|
+
setupEpoch(l1TxUtils: L1TxUtils) {
|
|
471
|
+
return l1TxUtils.sendAndMonitorTransaction({
|
|
472
|
+
to: this.address,
|
|
473
|
+
data: encodeFunctionData({
|
|
474
|
+
abi: RollupAbi,
|
|
475
|
+
functionName: 'setupEpoch',
|
|
476
|
+
args: [],
|
|
477
|
+
}),
|
|
478
|
+
});
|
|
479
|
+
}
|
|
453
480
|
}
|
|
@@ -1,19 +1,35 @@
|
|
|
1
1
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
|
+
import { retryUntil } from '@aztec/foundation/retry';
|
|
2
3
|
import { SlashingProposerAbi } from '@aztec/l1-artifacts/SlashingProposerAbi';
|
|
3
4
|
|
|
4
|
-
import
|
|
5
|
+
import EventEmitter from 'events';
|
|
6
|
+
import {
|
|
7
|
+
type EncodeFunctionDataParameters,
|
|
8
|
+
type GetContractReturnType,
|
|
9
|
+
type Hex,
|
|
10
|
+
encodeFunctionData,
|
|
11
|
+
getContract,
|
|
12
|
+
} from 'viem';
|
|
5
13
|
|
|
6
|
-
import type { L1TxRequest } from '../l1_tx_utils.js';
|
|
14
|
+
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils.js';
|
|
7
15
|
import type { ViemClient } from '../types.js';
|
|
16
|
+
import { FormattedViemError } from '../utils.js';
|
|
8
17
|
import { type IEmpireBase, encodeVote } from './empire_base.js';
|
|
9
18
|
|
|
10
|
-
export class
|
|
19
|
+
export class ProposalAlreadyExecutedError extends Error {
|
|
20
|
+
constructor(round: bigint) {
|
|
21
|
+
super(`Proposal already executed: ${round}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class SlashingProposerContract extends EventEmitter implements IEmpireBase {
|
|
11
26
|
private readonly proposer: GetContractReturnType<typeof SlashingProposerAbi, ViemClient>;
|
|
12
27
|
|
|
13
28
|
constructor(
|
|
14
29
|
public readonly client: ViemClient,
|
|
15
30
|
address: Hex,
|
|
16
31
|
) {
|
|
32
|
+
super();
|
|
17
33
|
this.proposer = getContract({ address, abi: SlashingProposerAbi, client });
|
|
18
34
|
}
|
|
19
35
|
|
|
@@ -45,10 +61,104 @@ export class SlashingProposerContract implements IEmpireBase {
|
|
|
45
61
|
};
|
|
46
62
|
}
|
|
47
63
|
|
|
64
|
+
public getProposalVotes(rollupAddress: Hex, round: bigint, proposal: Hex): Promise<bigint> {
|
|
65
|
+
return this.proposer.read.yeaCount([rollupAddress, round, proposal]);
|
|
66
|
+
}
|
|
67
|
+
|
|
48
68
|
public createVoteRequest(payload: Hex): L1TxRequest {
|
|
49
69
|
return {
|
|
50
70
|
to: this.address.toString(),
|
|
51
71
|
data: encodeVote(payload),
|
|
52
72
|
};
|
|
53
73
|
}
|
|
74
|
+
|
|
75
|
+
public listenToExecutableProposals(callback: (args: { proposal: `0x${string}`; round: bigint }) => unknown) {
|
|
76
|
+
return this.proposer.watchEvent.ProposalExecutable(
|
|
77
|
+
{},
|
|
78
|
+
{
|
|
79
|
+
onLogs: logs => {
|
|
80
|
+
for (const payload of logs) {
|
|
81
|
+
const args = payload.args;
|
|
82
|
+
if (args.proposal && args.round) {
|
|
83
|
+
// why compiler can't figure it out? no one knows
|
|
84
|
+
callback(args as { proposal: `0x${string}`; round: bigint });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public listenToProposalExecuted(callback: (args: { round: bigint; proposal: `0x${string}` }) => unknown) {
|
|
93
|
+
return this.proposer.watchEvent.ProposalExecuted(
|
|
94
|
+
{},
|
|
95
|
+
{
|
|
96
|
+
onLogs: logs => {
|
|
97
|
+
for (const payload of logs) {
|
|
98
|
+
const args = payload.args;
|
|
99
|
+
if (args.round && args.proposal) {
|
|
100
|
+
callback(args as { round: bigint; proposal: `0x${string}` });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public waitForRound(round: bigint, pollingIntervalSeconds: number = 1) {
|
|
109
|
+
return retryUntil(
|
|
110
|
+
async () => {
|
|
111
|
+
const currentRound = await this.proposer.read.getCurrentRound();
|
|
112
|
+
return currentRound >= round;
|
|
113
|
+
},
|
|
114
|
+
`Waiting for round ${round} to be reached`,
|
|
115
|
+
0, // no timeout
|
|
116
|
+
pollingIntervalSeconds,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public async executeRound(txUtils: L1TxUtils, round: bigint | number): Promise<void> {
|
|
121
|
+
if (typeof round === 'number') {
|
|
122
|
+
round = BigInt(round);
|
|
123
|
+
}
|
|
124
|
+
const args: EncodeFunctionDataParameters<typeof SlashingProposerAbi, 'executeProposal'> = {
|
|
125
|
+
abi: SlashingProposerAbi,
|
|
126
|
+
functionName: 'executeProposal',
|
|
127
|
+
args: [round],
|
|
128
|
+
};
|
|
129
|
+
const data = encodeFunctionData(args);
|
|
130
|
+
const response = await txUtils
|
|
131
|
+
.sendAndMonitorTransaction(
|
|
132
|
+
{
|
|
133
|
+
to: this.address.toString(),
|
|
134
|
+
data,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
// Gas estimation is more than 20% off for this tx.
|
|
138
|
+
gasLimitBufferPercentage: 100,
|
|
139
|
+
},
|
|
140
|
+
)
|
|
141
|
+
.catch(err => {
|
|
142
|
+
if (err instanceof FormattedViemError && err.message.includes('ProposalAlreadyExecuted')) {
|
|
143
|
+
throw new ProposalAlreadyExecutedError(round);
|
|
144
|
+
}
|
|
145
|
+
throw err;
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
if (response.receipt.status === 'reverted') {
|
|
149
|
+
const error = await txUtils.tryGetErrorFromRevertedTx(
|
|
150
|
+
data,
|
|
151
|
+
{
|
|
152
|
+
...args,
|
|
153
|
+
address: this.address.toString(),
|
|
154
|
+
},
|
|
155
|
+
undefined,
|
|
156
|
+
[],
|
|
157
|
+
);
|
|
158
|
+
if (error?.includes('ProposalAlreadyExecuted')) {
|
|
159
|
+
throw new ProposalAlreadyExecutedError(round);
|
|
160
|
+
}
|
|
161
|
+
throw new Error(error ?? 'Unknown error');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
54
164
|
}
|