@aztec/ethereum 0.0.1-commit.9ef841308 → 0.0.1-commit.a89ec08
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 +1 -1
- package/dest/contracts/multicall.d.ts +2 -51
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +0 -85
- package/dest/contracts/rollup.d.ts +1 -2
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +2 -8
- package/dest/generated/l1-contracts-defaults.d.ts +1 -1
- package/dest/generated/l1-contracts-defaults.js +1 -1
- package/dest/l1_artifacts.d.ts +69 -69
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +1 -3
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +25 -33
- package/dest/publisher_manager.d.ts +7 -21
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +7 -81
- package/dest/test/rollup_cheat_codes.d.ts +5 -1
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +9 -1
- package/dest/utils.d.ts +1 -1
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +12 -16
- package/package.json +7 -5
- package/src/config.ts +1 -1
- package/src/contracts/multicall.ts +1 -65
- package/src/contracts/rollup.ts +1 -7
- package/src/generated/l1-contracts-defaults.ts +1 -1
- package/src/l1_tx_utils/l1_tx_utils.ts +13 -23
- package/src/publisher_manager.ts +10 -105
- package/src/test/rollup_cheat_codes.ts +11 -1
- package/src/utils.ts +14 -17
|
@@ -31,10 +31,18 @@ import { EthCheatCodes } from './eth_cheat_codes.js';
|
|
|
31
31
|
}
|
|
32
32
|
/** Returns the current slot */ async getSlot() {
|
|
33
33
|
const ts = BigInt((await this.client.getBlock()).timestamp);
|
|
34
|
+
return this.getSlotAt(ts);
|
|
35
|
+
}
|
|
36
|
+
/** Returns the slot number at a given timestamp. */ async getSlotAt(timestamp) {
|
|
34
37
|
return SlotNumber.fromBigInt(await this.rollup.read.getSlotAt([
|
|
35
|
-
|
|
38
|
+
timestamp
|
|
36
39
|
]));
|
|
37
40
|
}
|
|
41
|
+
/** Returns the timestamp for the start of a given slot. */ async getTimestampForSlot(slot) {
|
|
42
|
+
return await this.rollup.read.getTimestampForSlot([
|
|
43
|
+
BigInt(slot)
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
38
46
|
/** Returns the number of seconds until the start of the given slot based on L1 block timestamp. */ async getSecondsUntilSlot(slot) {
|
|
39
47
|
const [currentTimestamp, targetTimestamp] = await Promise.all([
|
|
40
48
|
this.client.getBlock().then((b)=>BigInt(b.timestamp)),
|
package/dest/utils.d.ts
CHANGED
|
@@ -35,4 +35,4 @@ export declare function isBlobTransaction(tx: FormattedTransaction): tx is Forma
|
|
|
35
35
|
* Calculates a percentile from an array of bigints
|
|
36
36
|
*/
|
|
37
37
|
export declare function calculatePercentile(values: bigint[], percentile: number): bigint;
|
|
38
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
38
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy91dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN6RCxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUdwRCxPQUFPLEVBQ0wsS0FBSyxHQUFHLEVBR1IsS0FBSyxpQkFBaUIsRUFFdEIsS0FBSyx3QkFBd0IsRUFDN0IsS0FBSyxvQkFBb0IsRUFDekIsS0FBSyxHQUFHLEVBQ1IsS0FBSyxHQUFHLEVBR1QsTUFBTSxNQUFNLENBQUM7QUFHZCxNQUFNLFdBQVcsT0FBTztJQUN0QixXQUFXLEVBQUUsRUFBRSxDQUFDO0lBQ2hCLFdBQVcsRUFBRSxFQUFFLENBQUM7SUFDaEIsV0FBVyxFQUFFLEdBQUcsQ0FBQztJQUNqQixnQkFBZ0IsRUFBRSxNQUFNLENBQUM7Q0FDMUI7QUFFRCxxQkFBYSxrQkFBbUIsU0FBUSxLQUFLO0lBQzNDLFlBQVksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDO0lBRXJCLFlBQVksT0FBTyxFQUFFLE1BQU0sRUFBRSxZQUFZLENBQUMsRUFBRSxHQUFHLEVBQUUsRUFJaEQ7Q0FDRjtBQUVELHdCQUFnQixZQUFZLENBQzFCLEtBQUssQ0FBQyxJQUFJLFNBQVMsR0FBRyxHQUFHLFNBQVMsT0FBTyxFQUFFLEVBQzNDLFVBQVUsU0FBUyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsRUFDMUMsVUFBVSxHQUFHLHdCQUF3QixDQUFDLElBQUksRUFBRSxVQUFVLEVBQUUsR0FBRyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxFQUUvRSxJQUFJLEVBQUUsR0FBRyxFQUFFLEVBQ1gsT0FBTyxFQUFFLEdBQUcsRUFDWixHQUFHLEVBQUUsSUFBSSxFQUNULFNBQVMsRUFBRSxVQUFVLEVBQ3JCLE1BQU0sQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLFVBQVUsS0FBSyxPQUFPLEVBQ3JDLE1BQU0sQ0FBQyxFQUFFLE1BQU0sR0FDZCxVQUFVLENBTVo7QUFFRCx3QkFBZ0IsZUFBZSxDQUM3QixLQUFLLENBQUMsSUFBSSxTQUFTLEdBQUcsR0FBRyxTQUFTLE9BQU8sRUFBRSxFQUMzQyxVQUFVLFNBQVMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLEVBQzFDLFVBQVUsR0FBRyx3QkFBd0IsQ0FBQyxJQUFJLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLENBQUMsRUFFL0UsSUFBSSxFQUFFLEdBQUcsRUFBRSxFQUNYLE9BQU8sRUFBRSxHQUFHLEVBQ1osR0FBRyxFQUFFLElBQUksRUFDVCxTQUFTLEVBQUUsVUFBVSxFQUNyQixNQUFNLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxVQUFVLEtBQUssT0FBTyxFQUNyQyxNQUFNLENBQUMsRUFBRSxNQUFNLEdBQ2QsVUFBVSxHQUFHLFNBQVMsQ0FnQnhCO0FBRUQsd0JBQWdCLHFCQUFxQixDQUFDLEdBQUcsRUFBRSxHQUFHLE9BVzdDO0FBRUQsd0JBQWdCLFNBQVMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLEdBQUcsR0FBRyxDQWUxQztBQTRERDs7Ozs7R0FLRztBQUNILHdCQUFnQixlQUFlLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxHQUFHLEdBQUUsR0FBZSxHQUFHLGtCQUFrQixDQXdFcEY7QUF5QkQsd0JBQWdCLHFCQUFxQixDQUFDLEdBQUcsRUFBRSxHQUFHLHNCQWE3QztBQUVEOzs7R0FHRztBQUNILHdCQUFnQixpQkFBaUIsQ0FBQyxFQUFFLEVBQUUsb0JBQW9CLEdBQUcsRUFBRSxJQUFJLG9CQUFvQixHQUFHO0lBQ3hGLGdCQUFnQixFQUFFLE1BQU0sQ0FBQztJQUN6QixtQkFBbUIsRUFBRSxTQUFTLEdBQUcsRUFBRSxDQUFDO0NBQ3JDLENBT0E7QUFFRDs7R0FFRztBQUNILHdCQUFnQixtQkFBbUIsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLEVBQUUsVUFBVSxFQUFFLE1BQU0sR0FBRyxNQUFNLENBT2hGIn0=
|
package/dest/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAGpD,OAAO,EACL,KAAK,GAAG,EAGR,KAAK,iBAAiB,EAEtB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,GAAG,EACR,KAAK,GAAG,EAGT,MAAM,MAAM,CAAC;AAGd,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,EAAE,CAAC;IAChB,WAAW,EAAE,EAAE,CAAC;IAChB,WAAW,EAAE,GAAG,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC;IAErB,YAAY,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,GAAG,EAAE,EAIhD;CACF;AAED,wBAAgB,YAAY,CAC1B,KAAK,CAAC,IAAI,SAAS,GAAG,GAAG,SAAS,OAAO,EAAE,EAC3C,UAAU,SAAS,iBAAiB,CAAC,IAAI,CAAC,EAC1C,UAAU,GAAG,wBAAwB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAE/E,IAAI,EAAE,GAAG,EAAE,EACX,OAAO,EAAE,GAAG,EACZ,GAAG,EAAE,IAAI,EACT,SAAS,EAAE,UAAU,EACrB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,EACrC,MAAM,CAAC,EAAE,MAAM,GACd,UAAU,CAMZ;AAED,wBAAgB,eAAe,CAC7B,KAAK,CAAC,IAAI,SAAS,GAAG,GAAG,SAAS,OAAO,EAAE,EAC3C,UAAU,SAAS,iBAAiB,CAAC,IAAI,CAAC,EAC1C,UAAU,GAAG,wBAAwB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAE/E,IAAI,EAAE,GAAG,EAAE,EACX,OAAO,EAAE,GAAG,EACZ,GAAG,EAAE,IAAI,EACT,SAAS,EAAE,UAAU,EACrB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,EACrC,MAAM,CAAC,EAAE,MAAM,GACd,UAAU,GAAG,SAAS,CAgBxB;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,GAAG,OAW7C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,CAe1C;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAGpD,OAAO,EACL,KAAK,GAAG,EAGR,KAAK,iBAAiB,EAEtB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,GAAG,EACR,KAAK,GAAG,EAGT,MAAM,MAAM,CAAC;AAGd,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,EAAE,CAAC;IAChB,WAAW,EAAE,EAAE,CAAC;IAChB,WAAW,EAAE,GAAG,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC;IAErB,YAAY,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,GAAG,EAAE,EAIhD;CACF;AAED,wBAAgB,YAAY,CAC1B,KAAK,CAAC,IAAI,SAAS,GAAG,GAAG,SAAS,OAAO,EAAE,EAC3C,UAAU,SAAS,iBAAiB,CAAC,IAAI,CAAC,EAC1C,UAAU,GAAG,wBAAwB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAE/E,IAAI,EAAE,GAAG,EAAE,EACX,OAAO,EAAE,GAAG,EACZ,GAAG,EAAE,IAAI,EACT,SAAS,EAAE,UAAU,EACrB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,EACrC,MAAM,CAAC,EAAE,MAAM,GACd,UAAU,CAMZ;AAED,wBAAgB,eAAe,CAC7B,KAAK,CAAC,IAAI,SAAS,GAAG,GAAG,SAAS,OAAO,EAAE,EAC3C,UAAU,SAAS,iBAAiB,CAAC,IAAI,CAAC,EAC1C,UAAU,GAAG,wBAAwB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAE/E,IAAI,EAAE,GAAG,EAAE,EACX,OAAO,EAAE,GAAG,EACZ,GAAG,EAAE,IAAI,EACT,SAAS,EAAE,UAAU,EACrB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,EACrC,MAAM,CAAC,EAAE,MAAM,GACd,UAAU,GAAG,SAAS,CAgBxB;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,GAAG,OAW7C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,CAe1C;AA4DD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,GAAE,GAAe,GAAG,kBAAkB,CAwEpF;AAyBD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,GAAG,sBAa7C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,oBAAoB,GAAG,EAAE,IAAI,oBAAoB,GAAG;IACxF,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,SAAS,GAAG,EAAE,CAAC;CACrC,CAOA;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAOhF"}
|
package/dest/utils.js
CHANGED
|
@@ -112,19 +112,6 @@ function getNestedErrorData(error) {
|
|
|
112
112
|
// Not found
|
|
113
113
|
return undefined;
|
|
114
114
|
}
|
|
115
|
-
/**
|
|
116
|
-
* Truncates an error message to a safe length for log renderers.
|
|
117
|
-
* LogExplorer can only render up to 2500 characters in its summary view.
|
|
118
|
-
* We cap at 2000 to leave room for decorating context added by callers.
|
|
119
|
-
*/ function truncateErrorMessage(message) {
|
|
120
|
-
const MAX = 2000;
|
|
121
|
-
const CHUNK = 950;
|
|
122
|
-
if (message.length <= MAX) {
|
|
123
|
-
return message;
|
|
124
|
-
}
|
|
125
|
-
const truncated = message.length - 2 * CHUNK;
|
|
126
|
-
return message.slice(0, CHUNK) + `...${truncated} characters truncated...` + message.slice(-CHUNK);
|
|
127
|
-
}
|
|
128
115
|
/**
|
|
129
116
|
* Formats a Viem error into a FormattedViemError instance.
|
|
130
117
|
* @param error - The error to format.
|
|
@@ -175,9 +162,18 @@ function getNestedErrorData(error) {
|
|
|
175
162
|
}
|
|
176
163
|
// If it's a regular Error instance, return it with its message
|
|
177
164
|
if (error instanceof Error) {
|
|
178
|
-
return new FormattedViemError(
|
|
179
|
-
}
|
|
180
|
-
|
|
165
|
+
return new FormattedViemError(error.message, error?.metaMessages);
|
|
166
|
+
}
|
|
167
|
+
const body = String(error);
|
|
168
|
+
const length = body.length;
|
|
169
|
+
// LogExplorer can only render up to 2500 characters in it's summary view. Try to keep the whole message below this number
|
|
170
|
+
// Limit the error to 2000 chacaters in order to allow code higher up to decorate this error with extra details (up to 500 characters)
|
|
171
|
+
if (length > 2000) {
|
|
172
|
+
const chunk = 950;
|
|
173
|
+
const truncated = length - 2 * chunk;
|
|
174
|
+
return new FormattedViemError(body.slice(0, chunk) + `...${truncated} characters truncated...` + body.slice(-1 * chunk));
|
|
175
|
+
}
|
|
176
|
+
return new FormattedViemError(body);
|
|
181
177
|
}
|
|
182
178
|
function stripAbis(obj) {
|
|
183
179
|
if (!obj || typeof obj !== 'object') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/ethereum",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.a89ec08",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./account": "./dest/account.js",
|
|
@@ -50,10 +50,11 @@
|
|
|
50
50
|
"../package.common.json"
|
|
51
51
|
],
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
54
|
-
"@aztec/constants": "0.0.1-commit.
|
|
55
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
56
|
-
"@aztec/l1-artifacts": "0.0.1-commit.
|
|
53
|
+
"@aztec/blob-lib": "0.0.1-commit.a89ec08",
|
|
54
|
+
"@aztec/constants": "0.0.1-commit.a89ec08",
|
|
55
|
+
"@aztec/foundation": "0.0.1-commit.a89ec08",
|
|
56
|
+
"@aztec/l1-artifacts": "0.0.1-commit.a89ec08",
|
|
57
|
+
"@viem/anvil": "^0.0.10",
|
|
57
58
|
"dotenv": "^16.0.3",
|
|
58
59
|
"lodash.chunk": "^4.2.0",
|
|
59
60
|
"lodash.pickby": "^4.5.0",
|
|
@@ -68,6 +69,7 @@
|
|
|
68
69
|
"@types/lodash.pickby": "^4",
|
|
69
70
|
"@types/node": "^22.15.17",
|
|
70
71
|
"@typescript/native-preview": "7.0.0-dev.20260113.1",
|
|
72
|
+
"@viem/anvil": "^0.0.10",
|
|
71
73
|
"get-port": "^7.1.0",
|
|
72
74
|
"jest": "^30.0.0",
|
|
73
75
|
"jest-mock-extended": "^4.0.0",
|
package/src/config.ts
CHANGED
|
@@ -263,7 +263,7 @@ export const genesisStateConfigMappings: ConfigMappingsType<GenesisStateConfig>
|
|
|
263
263
|
},
|
|
264
264
|
prefundAddresses: {
|
|
265
265
|
env: 'PREFUND_ADDRESSES',
|
|
266
|
-
description: 'Comma-separated list of Aztec addresses to prefund with fee juice at genesis
|
|
266
|
+
description: 'Comma-separated list of Aztec addresses to prefund with fee juice at genesis.',
|
|
267
267
|
parseEnv: (val: string) =>
|
|
268
268
|
val
|
|
269
269
|
.split(',')
|
|
@@ -2,7 +2,7 @@ import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
|
2
2
|
import { TimeoutError } from '@aztec/foundation/error';
|
|
3
3
|
import type { Logger } from '@aztec/foundation/log';
|
|
4
4
|
|
|
5
|
-
import { type
|
|
5
|
+
import { type EncodeFunctionDataParameters, type Hex, encodeFunctionData, multicall3Abi } from 'viem';
|
|
6
6
|
|
|
7
7
|
import type { L1BlobInputs, L1TxConfig, L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
8
8
|
import type { ExtendedViemWalletClient } from '../types.js';
|
|
@@ -11,39 +11,6 @@ import { RollupContract } from './rollup.js';
|
|
|
11
11
|
|
|
12
12
|
export const MULTI_CALL_3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11' as const;
|
|
13
13
|
|
|
14
|
-
/** ABI fragment for aggregate3Value — not included in viem's multicall3Abi. */
|
|
15
|
-
export const aggregate3ValueAbi = [
|
|
16
|
-
{
|
|
17
|
-
inputs: [
|
|
18
|
-
{
|
|
19
|
-
components: [
|
|
20
|
-
{ internalType: 'address', name: 'target', type: 'address' },
|
|
21
|
-
{ internalType: 'bool', name: 'allowFailure', type: 'bool' },
|
|
22
|
-
{ internalType: 'uint256', name: 'value', type: 'uint256' },
|
|
23
|
-
{ internalType: 'bytes', name: 'callData', type: 'bytes' },
|
|
24
|
-
],
|
|
25
|
-
internalType: 'struct Multicall3.Call3Value[]',
|
|
26
|
-
name: 'calls',
|
|
27
|
-
type: 'tuple[]',
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
name: 'aggregate3Value',
|
|
31
|
-
outputs: [
|
|
32
|
-
{
|
|
33
|
-
components: [
|
|
34
|
-
{ internalType: 'bool', name: 'success', type: 'bool' },
|
|
35
|
-
{ internalType: 'bytes', name: 'returnData', type: 'bytes' },
|
|
36
|
-
],
|
|
37
|
-
internalType: 'struct Multicall3.Result[]',
|
|
38
|
-
name: 'returnData',
|
|
39
|
-
type: 'tuple[]',
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
stateMutability: 'payable',
|
|
43
|
-
type: 'function',
|
|
44
|
-
},
|
|
45
|
-
] as const;
|
|
46
|
-
|
|
47
14
|
export class Multicall3 {
|
|
48
15
|
static async forward(
|
|
49
16
|
requests: L1TxRequest[],
|
|
@@ -155,37 +122,6 @@ export class Multicall3 {
|
|
|
155
122
|
throw err;
|
|
156
123
|
}
|
|
157
124
|
}
|
|
158
|
-
|
|
159
|
-
/** Batch multiple value transfers into a single aggregate3Value call on Multicall3. */
|
|
160
|
-
static async forwardValue(calls: { to: Address; value: bigint }[], l1TxUtils: L1TxUtils, logger: Logger) {
|
|
161
|
-
const args = calls.map(c => ({
|
|
162
|
-
target: c.to,
|
|
163
|
-
allowFailure: false,
|
|
164
|
-
value: c.value,
|
|
165
|
-
callData: '0x' as Hex,
|
|
166
|
-
}));
|
|
167
|
-
|
|
168
|
-
const data = encodeFunctionData({
|
|
169
|
-
abi: aggregate3ValueAbi,
|
|
170
|
-
functionName: 'aggregate3Value',
|
|
171
|
-
args: [args],
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
const totalValue = calls.reduce((sum, c) => sum + c.value, 0n);
|
|
175
|
-
|
|
176
|
-
logger.info(`Sending aggregate3Value with ${calls.length} calls`, { totalValue });
|
|
177
|
-
const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
|
|
178
|
-
to: MULTI_CALL_3_ADDRESS,
|
|
179
|
-
data,
|
|
180
|
-
value: totalValue,
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
if (receipt.status !== 'success') {
|
|
184
|
-
throw new Error(`aggregate3Value transaction reverted: ${receipt.transactionHash}`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return { receipt };
|
|
188
|
-
}
|
|
189
125
|
}
|
|
190
126
|
|
|
191
127
|
export async function deployMulticall3(l1Client: ExtendedViemWalletClient, logger: Logger) {
|
package/src/contracts/rollup.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
4
4
|
import { memoize } from '@aztec/foundation/decorators';
|
|
5
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
6
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
7
|
-
import { createLogger } from '@aztec/foundation/log';
|
|
8
7
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
9
8
|
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
10
9
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
@@ -213,7 +212,6 @@ export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
|
213
212
|
|
|
214
213
|
export class RollupContract {
|
|
215
214
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
216
|
-
private readonly logger = createLogger('ethereum:rollup');
|
|
217
215
|
|
|
218
216
|
private static cachedStfStorageSlot: Hex | undefined;
|
|
219
217
|
private cachedEscapeHatch?: {
|
|
@@ -497,11 +495,7 @@ export class RollupContract {
|
|
|
497
495
|
|
|
498
496
|
const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
|
|
499
497
|
return isOpen;
|
|
500
|
-
} catch
|
|
501
|
-
this.logger.warn('isEscapeHatchOpen failed (treating as closed); RPC or contract error may cause liveness risk', {
|
|
502
|
-
epoch: Number(epoch),
|
|
503
|
-
error: err,
|
|
504
|
-
});
|
|
498
|
+
} catch {
|
|
505
499
|
return false;
|
|
506
500
|
}
|
|
507
501
|
}
|
|
@@ -8,7 +8,7 @@ export const l1ContractsDefaultEnv = {
|
|
|
8
8
|
AZTEC_EPOCH_DURATION: 32,
|
|
9
9
|
AZTEC_TARGET_COMMITTEE_SIZE: 48,
|
|
10
10
|
AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET: 2,
|
|
11
|
-
AZTEC_LAG_IN_EPOCHS_FOR_RANDAO:
|
|
11
|
+
AZTEC_LAG_IN_EPOCHS_FOR_RANDAO: 1,
|
|
12
12
|
AZTEC_ACTIVATION_THRESHOLD: 100000000000000000000,
|
|
13
13
|
AZTEC_EJECTION_THRESHOLD: 50000000000000000000,
|
|
14
14
|
AZTEC_LOCAL_EJECTION_THRESHOLD: 98000000000000000000,
|
|
@@ -4,7 +4,6 @@ import { merge, pick } from '@aztec/foundation/collection';
|
|
|
4
4
|
import { InterruptError, TimeoutError } from '@aztec/foundation/error';
|
|
5
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
6
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
7
|
-
import { Semaphore } from '@aztec/foundation/queue';
|
|
8
7
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
9
8
|
import { sleep } from '@aztec/foundation/sleep';
|
|
10
9
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
@@ -48,8 +47,6 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
48
47
|
protected txs: L1TxState[] = [];
|
|
49
48
|
/** Last nonce successfully sent to the chain. Used as a lower bound when a fallback RPC node returns a stale count. */
|
|
50
49
|
private lastSentNonce: number | undefined;
|
|
51
|
-
/** Mutex to prevent concurrent sendTransaction calls from racing on the same nonce. */
|
|
52
|
-
private readonly sendMutex = new Semaphore(1);
|
|
53
50
|
/** Tx delayer for testing. Only set when enableDelayer config is true. */
|
|
54
51
|
public delayer?: Delayer;
|
|
55
52
|
/** KZG instance for blob operations. */
|
|
@@ -256,27 +253,20 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
256
253
|
);
|
|
257
254
|
}
|
|
258
255
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
256
|
+
const chainNonce = await this.client.getTransactionCount({ address: account, blockTag: 'pending' });
|
|
257
|
+
// If a fallback RPC node returns a stale count (lower than what we last sent), use our
|
|
258
|
+
// local lower bound to avoid sending a duplicate of an already-pending transaction.
|
|
259
|
+
const nonce =
|
|
260
|
+
this.lastSentNonce !== undefined && chainNonce <= this.lastSentNonce ? this.lastSentNonce + 1 : chainNonce;
|
|
262
261
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
baseState = { request, gasLimit, blobInputs, gasPrice, nonce };
|
|
272
|
-
const txData = this.makeTxData(baseState, { isCancelTx: false });
|
|
273
|
-
|
|
274
|
-
const signedRequest = await this.prepareSignedTransaction(txData);
|
|
275
|
-
txHash = await this.client.sendRawTransaction({ serializedTransaction: signedRequest });
|
|
276
|
-
this.lastSentNonce = nonce;
|
|
277
|
-
} finally {
|
|
278
|
-
this.sendMutex.release();
|
|
279
|
-
}
|
|
262
|
+
const baseState = { request, gasLimit, blobInputs, gasPrice, nonce };
|
|
263
|
+
const txData = this.makeTxData(baseState, { isCancelTx: false });
|
|
264
|
+
|
|
265
|
+
// Send the new tx
|
|
266
|
+
const signedRequest = await this.prepareSignedTransaction(txData);
|
|
267
|
+
const txHash = await this.client.sendRawTransaction({ serializedTransaction: signedRequest });
|
|
268
|
+
// Update after tx is sent successfully
|
|
269
|
+
this.lastSentNonce = nonce;
|
|
280
270
|
|
|
281
271
|
// Create the new state for monitoring
|
|
282
272
|
const l1TxState: L1TxState = {
|
package/src/publisher_manager.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { pick } from '@aztec/foundation/collection';
|
|
2
2
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
|
-
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
4
3
|
|
|
5
|
-
import { Multicall3 } from './contracts/multicall.js';
|
|
6
4
|
import { L1TxUtils, TxUtilsState } from './l1_tx_utils/index.js';
|
|
7
5
|
|
|
8
6
|
// Defines the order in which we prioritise publishers based on their state (first is better)
|
|
@@ -29,72 +27,24 @@ const busyStates: TxUtilsState[] = [
|
|
|
29
27
|
|
|
30
28
|
export type PublisherFilter<UtilsType extends L1TxUtils> = (utils: UtilsType) => boolean;
|
|
31
29
|
|
|
32
|
-
/** Config accepted by PublisherManager. */
|
|
33
|
-
type PublisherManagerConfig = {
|
|
34
|
-
publisherAllowInvalidStates?: boolean;
|
|
35
|
-
publisherFundingThreshold?: bigint;
|
|
36
|
-
publisherFundingAmount?: bigint;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
30
|
export class PublisherManager<UtilsType extends L1TxUtils = L1TxUtils> {
|
|
40
31
|
private log: Logger;
|
|
41
|
-
private config:
|
|
42
|
-
private static readonly FUNDING_CHECK_INTERVAL_MS = 2 * 60 * 1000;
|
|
43
|
-
private funder?: UtilsType;
|
|
44
|
-
private fundingPromise?: RunningPromise;
|
|
32
|
+
private config: { publisherAllowInvalidStates?: boolean };
|
|
45
33
|
|
|
46
34
|
constructor(
|
|
47
35
|
private publishers: UtilsType[],
|
|
48
|
-
config:
|
|
49
|
-
|
|
36
|
+
config: { publisherAllowInvalidStates?: boolean },
|
|
37
|
+
bindings?: LoggerBindings,
|
|
50
38
|
) {
|
|
51
|
-
this.
|
|
52
|
-
this.log = createLogger('publisher:manager', opts?.bindings);
|
|
39
|
+
this.log = createLogger('publisher:manager', bindings);
|
|
53
40
|
this.log.info(`PublisherManager initialized with ${publishers.length} publishers.`);
|
|
54
41
|
this.publishers = publishers;
|
|
55
|
-
this.config = pick(config, 'publisherAllowInvalidStates'
|
|
56
|
-
|
|
57
|
-
const hasThreshold = this.config.publisherFundingThreshold !== undefined;
|
|
58
|
-
const hasAmount = this.config.publisherFundingAmount !== undefined;
|
|
59
|
-
if (hasThreshold !== hasAmount) {
|
|
60
|
-
this.log.warn(`Incomplete funding config: both publisherFundingThreshold and publisherFundingAmount must be set`);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (this.funder) {
|
|
64
|
-
const funderAddress = this.funder.getSenderAddress();
|
|
65
|
-
if (publishers.some(p => p.getSenderAddress().equals(funderAddress))) {
|
|
66
|
-
this.log.error(`Funding account ${funderAddress} is also a publisher, disabling funding to avoid self-funding`);
|
|
67
|
-
this.funder = undefined;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
42
|
+
this.config = pick(config, 'publisherAllowInvalidStates');
|
|
70
43
|
}
|
|
71
44
|
|
|
72
|
-
/** Loads the state of all publishers and
|
|
73
|
-
public async
|
|
74
|
-
await Promise.all(
|
|
75
|
-
...this.publishers.map(pub => pub.loadStateAndResumeMonitoring()),
|
|
76
|
-
this.funder?.loadStateAndResumeMonitoring(),
|
|
77
|
-
]);
|
|
78
|
-
|
|
79
|
-
if (
|
|
80
|
-
this.funder &&
|
|
81
|
-
this.config.publisherFundingThreshold !== undefined &&
|
|
82
|
-
this.config.publisherFundingAmount !== undefined
|
|
83
|
-
) {
|
|
84
|
-
this.fundingPromise = new RunningPromise(
|
|
85
|
-
() => this.triggerFundingIfNeeded(),
|
|
86
|
-
this.log,
|
|
87
|
-
PublisherManager.FUNDING_CHECK_INTERVAL_MS,
|
|
88
|
-
);
|
|
89
|
-
this.fundingPromise.start();
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** Stops the funding loop and interrupts all publishers. */
|
|
94
|
-
public async stop(): Promise<void> {
|
|
95
|
-
await this.fundingPromise?.stop();
|
|
96
|
-
this.publishers.forEach(pub => pub.interrupt());
|
|
97
|
-
this.funder?.interrupt();
|
|
45
|
+
/** Loads the state of all publishers and resumes monitoring any pending txs */
|
|
46
|
+
public async loadState(): Promise<void> {
|
|
47
|
+
await Promise.all(this.publishers.map(pub => pub.loadStateAndResumeMonitoring()));
|
|
98
48
|
}
|
|
99
49
|
|
|
100
50
|
// Finds and prioritises available publishers based on
|
|
@@ -152,52 +102,7 @@ export class PublisherManager<UtilsType extends L1TxUtils = L1TxUtils> {
|
|
|
152
102
|
return sortedPublishers[0].publisher;
|
|
153
103
|
}
|
|
154
104
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const { funder, config } = this;
|
|
158
|
-
if (!funder || config.publisherFundingThreshold === undefined || config.publisherFundingAmount === undefined) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const allBalances = await Promise.all(
|
|
163
|
-
this.publishers.map(async pub => ({ balance: await pub.getSenderBalance(), publisher: pub })),
|
|
164
|
-
);
|
|
165
|
-
const lowBalance = allBalances.filter(p => p.balance < config.publisherFundingThreshold!);
|
|
166
|
-
if (lowBalance.length === 0) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const fundingAmount = config.publisherFundingAmount!;
|
|
171
|
-
const funderBalance = await funder.getSenderBalance();
|
|
172
|
-
|
|
173
|
-
if (funderBalance < 10n * fundingAmount) {
|
|
174
|
-
this.log.warn(`Funding account balance is low`, { funderBalance, threshold: 10n * fundingAmount });
|
|
175
|
-
}
|
|
176
|
-
const affordableCount = Number(funderBalance / fundingAmount);
|
|
177
|
-
if (affordableCount === 0) {
|
|
178
|
-
this.log.error(`Funding account balance too low to fund any publisher`, { funderBalance, fundingAmount });
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
if (affordableCount < lowBalance.length) {
|
|
182
|
-
this.log.warn(`Funder can only afford ${affordableCount}/${lowBalance.length} publishers`, {
|
|
183
|
-
funderBalance,
|
|
184
|
-
fundingAmount,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const toFund = lowBalance.slice(0, affordableCount).map(p => p.publisher);
|
|
189
|
-
await this.fundPublishers(toFund);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/** Fund publishers via a single Multicall3 aggregate3Value transaction. */
|
|
193
|
-
private async fundPublishers(publishers: UtilsType[]): Promise<void> {
|
|
194
|
-
const fundingAmount = this.config.publisherFundingAmount!;
|
|
195
|
-
const calls = publishers.map(pub => ({
|
|
196
|
-
to: pub.getSenderAddress().toString(),
|
|
197
|
-
value: fundingAmount,
|
|
198
|
-
}));
|
|
199
|
-
|
|
200
|
-
await Multicall3.forwardValue(calls, this.funder!, this.log);
|
|
201
|
-
this.log.info(`Funded ${publishers.length} publishers`);
|
|
105
|
+
public interrupt() {
|
|
106
|
+
this.publishers.forEach(pub => pub.interrupt());
|
|
202
107
|
}
|
|
203
108
|
}
|
|
@@ -53,7 +53,17 @@ export class RollupCheatCodes {
|
|
|
53
53
|
/** Returns the current slot */
|
|
54
54
|
public async getSlot(): Promise<SlotNumber> {
|
|
55
55
|
const ts = BigInt((await this.client.getBlock()).timestamp);
|
|
56
|
-
return
|
|
56
|
+
return this.getSlotAt(ts);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Returns the slot number at a given timestamp. */
|
|
60
|
+
public async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
|
|
61
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getSlotAt([timestamp]));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Returns the timestamp for the start of a given slot. */
|
|
65
|
+
public async getTimestampForSlot(slot: SlotNumber): Promise<bigint> {
|
|
66
|
+
return await this.rollup.read.getTimestampForSlot([BigInt(slot)]);
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
/** Returns the number of seconds until the start of the given slot based on L1 block timestamp. */
|
package/src/utils.ts
CHANGED
|
@@ -170,21 +170,6 @@ function getNestedErrorData(error: unknown): string | undefined {
|
|
|
170
170
|
return undefined;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
/**
|
|
174
|
-
* Truncates an error message to a safe length for log renderers.
|
|
175
|
-
* LogExplorer can only render up to 2500 characters in its summary view.
|
|
176
|
-
* We cap at 2000 to leave room for decorating context added by callers.
|
|
177
|
-
*/
|
|
178
|
-
function truncateErrorMessage(message: string): string {
|
|
179
|
-
const MAX = 2000;
|
|
180
|
-
const CHUNK = 950;
|
|
181
|
-
if (message.length <= MAX) {
|
|
182
|
-
return message;
|
|
183
|
-
}
|
|
184
|
-
const truncated = message.length - 2 * CHUNK;
|
|
185
|
-
return message.slice(0, CHUNK) + `...${truncated} characters truncated...` + message.slice(-CHUNK);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
173
|
/**
|
|
189
174
|
* Formats a Viem error into a FormattedViemError instance.
|
|
190
175
|
* @param error - The error to format.
|
|
@@ -247,10 +232,22 @@ export function formatViemError(error: any, abi: Abi = ErrorsAbi): FormattedViem
|
|
|
247
232
|
|
|
248
233
|
// If it's a regular Error instance, return it with its message
|
|
249
234
|
if (error instanceof Error) {
|
|
250
|
-
return new FormattedViemError(
|
|
235
|
+
return new FormattedViemError(error.message, (error as any)?.metaMessages);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const body = String(error);
|
|
239
|
+
const length = body.length;
|
|
240
|
+
// LogExplorer can only render up to 2500 characters in it's summary view. Try to keep the whole message below this number
|
|
241
|
+
// Limit the error to 2000 chacaters in order to allow code higher up to decorate this error with extra details (up to 500 characters)
|
|
242
|
+
if (length > 2000) {
|
|
243
|
+
const chunk = 950;
|
|
244
|
+
const truncated = length - 2 * chunk;
|
|
245
|
+
return new FormattedViemError(
|
|
246
|
+
body.slice(0, chunk) + `...${truncated} characters truncated...` + body.slice(-1 * chunk),
|
|
247
|
+
);
|
|
251
248
|
}
|
|
252
249
|
|
|
253
|
-
return new FormattedViemError(
|
|
250
|
+
return new FormattedViemError(body);
|
|
254
251
|
}
|
|
255
252
|
|
|
256
253
|
function stripAbis(obj: any) {
|