@aztec/sequencer-client 5.3.0-nightly.20260821 → 5.3.0-nightly.20260822
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/global_variable_builder/fee_predictor.d.ts +26 -14
- package/dest/global_variable_builder/fee_predictor.d.ts.map +1 -1
- package/dest/global_variable_builder/fee_predictor.js +15 -26
- package/dest/global_variable_builder/fee_provider.d.ts +9 -2
- package/dest/global_variable_builder/fee_provider.d.ts.map +1 -1
- package/dest/global_variable_builder/fee_provider.js +41 -34
- package/package.json +27 -27
- package/src/global_variable_builder/fee_predictor.ts +20 -26
- package/src/global_variable_builder/fee_provider.ts +44 -37
|
@@ -1,37 +1,49 @@
|
|
|
1
|
-
import { type RollupContract } from '@aztec/ethereum/contracts';
|
|
1
|
+
import { type L1FeeData, type RollupContract } from '@aztec/ethereum/contracts';
|
|
2
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import type { DateProvider } from '@aztec/foundation/timer';
|
|
3
4
|
import { GasFees, ManaUsageEstimate } from '@aztec/stdlib/gas';
|
|
5
|
+
/** Cached rollup state for fee prediction. Refreshed once per L1 block. */
|
|
6
|
+
type FeeOracleState = {
|
|
7
|
+
lastSlot: SlotNumber;
|
|
8
|
+
excessMana: bigint;
|
|
9
|
+
ethPerFeeAsset: bigint;
|
|
10
|
+
manaTarget: bigint;
|
|
11
|
+
manaLimit: bigint;
|
|
12
|
+
provingCostPerManaEth: bigint;
|
|
13
|
+
epochDuration: bigint;
|
|
14
|
+
/** Pre-resolved L1 fees for each slot in the prediction window. */
|
|
15
|
+
l1FeesBySlot: L1FeeData[];
|
|
16
|
+
};
|
|
4
17
|
/**
|
|
5
18
|
* Predicts min fees for LAG upcoming slots based on the L1 oracle state.
|
|
6
19
|
* A new oracle update can activate at startSlot + LAG, so only the first LAG entries
|
|
7
|
-
* are guaranteed stable.
|
|
8
|
-
* for each mana usage estimate.
|
|
20
|
+
* are guaranteed stable.
|
|
9
21
|
*/
|
|
10
22
|
export declare class FeePredictor {
|
|
11
23
|
private readonly rollupContract;
|
|
12
|
-
private readonly publicClient;
|
|
13
24
|
private readonly dateProvider;
|
|
14
25
|
private cachedState;
|
|
15
|
-
private cachedL1BlockNumber;
|
|
16
26
|
private readonly slotDuration;
|
|
17
27
|
private readonly l1GenesisTime;
|
|
18
28
|
private readonly ethereumSlotDuration;
|
|
19
|
-
constructor(rollupContract: RollupContract,
|
|
20
|
-
getBlockNumber: (opts?: {
|
|
21
|
-
cacheTime?: number;
|
|
22
|
-
}) => Promise<bigint>;
|
|
23
|
-
}, dateProvider: DateProvider, config: {
|
|
29
|
+
constructor(rollupContract: RollupContract, dateProvider: DateProvider, config: {
|
|
24
30
|
slotDuration: number;
|
|
25
31
|
l1GenesisTime: bigint;
|
|
26
32
|
ethereumSlotDuration: number;
|
|
27
33
|
});
|
|
28
|
-
/** Returns predicted min fees for each slot in the prediction window. */
|
|
29
|
-
getPredictedMinFees(manaUsage: ManaUsageEstimate):
|
|
30
|
-
|
|
34
|
+
/** Returns predicted min fees for each slot in the prediction window, from the cached state. */
|
|
35
|
+
getPredictedMinFees(manaUsage: ManaUsageEstimate): GasFees[];
|
|
36
|
+
/** Returns whatever rollup state is currently cached, or undefined if refreshState() has never been called. */
|
|
37
|
+
getState(): FeeOracleState | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Fetches and caches rollup state for the given L1 block.
|
|
40
|
+
*/
|
|
41
|
+
refreshState(blockNumber: bigint): Promise<FeeOracleState>;
|
|
31
42
|
private fetchState;
|
|
32
43
|
/** Computes per-slot fee predictions given cached state and a mana usage assumption. */
|
|
33
44
|
private computePredictions;
|
|
34
45
|
private getAssumedManaUsed;
|
|
35
46
|
private computeGasFees;
|
|
36
47
|
}
|
|
37
|
-
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmVlX3ByZWRpY3Rvci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2dsb2JhbF92YXJpYWJsZV9idWlsZGVyL2ZlZV9wcmVkaWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssU0FBUyxFQUFvQyxLQUFLLGNBQWMsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2xILE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUU3RCxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUU1RCxPQUFPLEVBRUwsT0FBTyxFQUVQLGlCQUFpQixFQUdsQixNQUFNLG1CQUFtQixDQUFDO0FBRTNCLDJFQUEyRTtBQUMzRSxLQUFLLGNBQWMsR0FBRztJQUNwQixRQUFRLEVBQUUsVUFBVSxDQUFDO0lBQ3JCLFVBQVUsRUFBRSxNQUFNLENBQUM7SUFDbkIsY0FBYyxFQUFFLE1BQU0sQ0FBQztJQUN2QixVQUFVLEVBQUUsTUFBTSxDQUFDO0lBQ25CLFNBQVMsRUFBRSxNQUFNLENBQUM7SUFDbEIscUJBQXFCLEVBQUUsTUFBTSxDQUFDO0lBQzlCLGFBQWEsRUFBRSxNQUFNLENBQUM7SUFDdEIsbUVBQW1FO0lBQ25FLFlBQVksRUFBRSxTQUFTLEVBQUUsQ0FBQztDQUMzQixDQUFDO0FBRUY7Ozs7R0FJRztBQUNILHFCQUFhLFlBQVk7SUFRckIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxjQUFjO0lBQy9CLE9BQU8sQ0FBQyxRQUFRLENBQUMsWUFBWTtJQVIvQixPQUFPLENBQUMsV0FBVyxDQUE2QjtJQUVoRCxPQUFPLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBUztJQUN0QyxPQUFPLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBUztJQUN2QyxPQUFPLENBQUMsUUFBUSxDQUFDLG9CQUFvQixDQUFTO0lBRTlDLFlBQ21CLGNBQWMsRUFBRSxjQUFjLEVBQzlCLFlBQVksRUFBRSxZQUFZLEVBQzNDLE1BQU0sRUFBRTtRQUFFLFlBQVksRUFBRSxNQUFNLENBQUM7UUFBQyxhQUFhLEVBQUUsTUFBTSxDQUFDO1FBQUMsb0JBQW9CLEVBQUUsTUFBTSxDQUFBO0tBQUUsRUFLdEY7SUFFRCxnR0FBZ0c7SUFDaEcsbUJBQW1CLENBQUMsU0FBUyxFQUFFLGlCQUFpQixHQUFHLE9BQU8sRUFBRSxDQU0zRDtJQUVELCtHQUErRztJQUMvRyxRQUFRLElBQUksY0FBYyxHQUFHLFNBQVMsQ0FFckM7SUFFRDs7T0FFRztJQUNHLFlBQVksQ0FBQyxXQUFXLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FJL0Q7WUFFYSxVQUFVO0lBaUR4Qix3RkFBd0Y7SUFDeEYsT0FBTyxDQUFDLGtCQUFrQjtJQXVCMUIsT0FBTyxDQUFDLGtCQUFrQjtJQVcxQixPQUFPLENBQUMsY0FBYztDQW1CdkIifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fee_predictor.d.ts","sourceRoot":"","sources":["../../src/global_variable_builder/fee_predictor.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"fee_predictor.d.ts","sourceRoot":"","sources":["../../src/global_variable_builder/fee_predictor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAoC,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAClH,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAEL,OAAO,EAEP,iBAAiB,EAGlB,MAAM,mBAAmB,CAAC;AAE3B,2EAA2E;AAC3E,KAAK,cAAc,GAAG;IACpB,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,YAAY,EAAE,SAAS,EAAE,CAAC;CAC3B,CAAC;AAEF;;;;GAIG;AACH,qBAAa,YAAY;IAQrB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAR/B,OAAO,CAAC,WAAW,CAA6B;IAEhD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAE9C,YACmB,cAAc,EAAE,cAAc,EAC9B,YAAY,EAAE,YAAY,EAC3C,MAAM,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,oBAAoB,EAAE,MAAM,CAAA;KAAE,EAKtF;IAED,gGAAgG;IAChG,mBAAmB,CAAC,SAAS,EAAE,iBAAiB,GAAG,OAAO,EAAE,CAM3D;IAED,+GAA+G;IAC/G,QAAQ,IAAI,cAAc,GAAG,SAAS,CAErC;IAED;;OAEG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAI/D;YAEa,UAAU;IAiDxB,wFAAwF;IACxF,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,cAAc;CAmBvB"}
|
|
@@ -6,49 +6,38 @@ import { FEE_ORACLE_LAG, GasFees, MIN_ETH_PER_FEE_ASSET, ManaUsageEstimate, comp
|
|
|
6
6
|
/**
|
|
7
7
|
* Predicts min fees for LAG upcoming slots based on the L1 oracle state.
|
|
8
8
|
* A new oracle update can activate at startSlot + LAG, so only the first LAG entries
|
|
9
|
-
* are guaranteed stable.
|
|
10
|
-
* for each mana usage estimate.
|
|
9
|
+
* are guaranteed stable.
|
|
11
10
|
*/ export class FeePredictor {
|
|
12
11
|
rollupContract;
|
|
13
|
-
publicClient;
|
|
14
12
|
dateProvider;
|
|
15
13
|
cachedState;
|
|
16
|
-
cachedL1BlockNumber;
|
|
17
14
|
slotDuration;
|
|
18
15
|
l1GenesisTime;
|
|
19
16
|
ethereumSlotDuration;
|
|
20
|
-
constructor(rollupContract,
|
|
17
|
+
constructor(rollupContract, dateProvider, config){
|
|
21
18
|
this.rollupContract = rollupContract;
|
|
22
|
-
this.publicClient = publicClient;
|
|
23
19
|
this.dateProvider = dateProvider;
|
|
24
20
|
this.slotDuration = config.slotDuration;
|
|
25
21
|
this.l1GenesisTime = config.l1GenesisTime;
|
|
26
22
|
this.ethereumSlotDuration = config.ethereumSlotDuration;
|
|
27
23
|
}
|
|
28
|
-
/** Returns predicted min fees for each slot in the prediction window. */
|
|
29
|
-
const state =
|
|
24
|
+
/** Returns predicted min fees for each slot in the prediction window, from the cached state. */ getPredictedMinFees(manaUsage) {
|
|
25
|
+
const state = this.getState();
|
|
26
|
+
if (state === undefined) {
|
|
27
|
+
throw new Error('FeePredictor.refreshState() must be called before getPredictedMinFees()');
|
|
28
|
+
}
|
|
30
29
|
return this.computePredictions(state, manaUsage);
|
|
31
30
|
}
|
|
32
|
-
/**
|
|
33
|
-
const blockNumber = await this.publicClient.getBlockNumber({
|
|
34
|
-
cacheTime: 0
|
|
35
|
-
});
|
|
36
|
-
if (this.cachedL1BlockNumber === undefined || blockNumber > this.cachedL1BlockNumber) {
|
|
37
|
-
this.cachedL1BlockNumber = blockNumber;
|
|
38
|
-
// Reset the cached block number on failure so a transient L1 RPC error does not leave a
|
|
39
|
-
// rejected promise cached for this block, which would replay the same rejection on every
|
|
40
|
-
// subsequent call until the next L1 block arrives. Only clear it if it still points at the
|
|
41
|
-
// block this attempt was for, so a stale rejection from an older block cannot wipe a marker
|
|
42
|
-
// a newer call already advanced (which would also defeat the monotonic block-number guard).
|
|
43
|
-
this.cachedState = this.fetchState(blockNumber).catch((err)=>{
|
|
44
|
-
if (this.cachedL1BlockNumber === blockNumber) {
|
|
45
|
-
this.cachedL1BlockNumber = undefined;
|
|
46
|
-
}
|
|
47
|
-
throw err;
|
|
48
|
-
});
|
|
49
|
-
}
|
|
31
|
+
/** Returns whatever rollup state is currently cached, or undefined if refreshState() has never been called. */ getState() {
|
|
50
32
|
return this.cachedState;
|
|
51
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Fetches and caches rollup state for the given L1 block.
|
|
36
|
+
*/ async refreshState(blockNumber) {
|
|
37
|
+
const state = await this.fetchState(blockNumber);
|
|
38
|
+
this.cachedState = state;
|
|
39
|
+
return state;
|
|
40
|
+
}
|
|
52
41
|
async fetchState(blockNumber) {
|
|
53
42
|
// Pin all non-constant queries to this L1 block number for a consistent snapshot.
|
|
54
43
|
const opts = {
|
|
@@ -3,19 +3,26 @@ import type { DateProvider } from '@aztec/foundation/timer';
|
|
|
3
3
|
import { GasFees, ManaUsageEstimate } from '@aztec/stdlib/gas';
|
|
4
4
|
import type { FeeProvider } from '@aztec/stdlib/tx';
|
|
5
5
|
import type { GlobalVariableBuilderConfig } from './global_builder.js';
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Provides current and predicted fee information based on on-chain state.
|
|
8
|
+
*/
|
|
7
9
|
export declare class FeeProviderImpl implements FeeProvider {
|
|
8
10
|
private readonly dateProvider;
|
|
9
11
|
private readonly publicClient;
|
|
10
12
|
private currentMinFees;
|
|
11
13
|
private currentL1BlockNumber;
|
|
14
|
+
private refreshLoop;
|
|
12
15
|
private readonly rollupContract;
|
|
13
16
|
private readonly feePredictor;
|
|
14
17
|
private readonly ethereumSlotDuration;
|
|
15
18
|
private readonly l1GenesisTime;
|
|
19
|
+
private readonly log;
|
|
16
20
|
constructor(dateProvider: DateProvider, publicClient: ViemPublicClient, config: GlobalVariableBuilderConfig);
|
|
21
|
+
start(pollingIntervalMs?: number): Promise<void>;
|
|
22
|
+
stop(): Promise<void>;
|
|
23
|
+
private refreshFromL1;
|
|
17
24
|
private computeCurrentMinFees;
|
|
18
25
|
getCurrentMinFees(): Promise<GasFees>;
|
|
19
26
|
getPredictedMinFees(manaUsage?: ManaUsageEstimate): Promise<GasFees[]>;
|
|
20
27
|
}
|
|
21
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmVlX3Byb3ZpZGVyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZ2xvYmFsX3ZhcmlhYmxlX2J1aWxkZXIvZmVlX3Byb3ZpZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFJOUQsT0FBTyxLQUFLLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFNUQsT0FBTyxFQUFFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQy9ELE9BQU8sS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBR3BELE9BQU8sS0FBSyxFQUFFLDJCQUEyQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFLdkU7O0dBRUc7QUFDSCxxQkFBYSxlQUFnQixZQUFXLFdBQVc7SUFZL0MsT0FBTyxDQUFDLFFBQVEsQ0FBQyxZQUFZO0lBQzdCLE9BQU8sQ0FBQyxRQUFRLENBQUMsWUFBWTtJQVovQixPQUFPLENBQUMsY0FBYyxDQUFxQjtJQUMzQyxPQUFPLENBQUMsb0JBQW9CLENBQWlDO0lBQzdELE9BQU8sQ0FBQyxXQUFXLENBQTZCO0lBRWhELE9BQU8sQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFpQjtJQUNoRCxPQUFPLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBZTtJQUM1QyxPQUFPLENBQUMsUUFBUSxDQUFDLG9CQUFvQixDQUFTO0lBQzlDLE9BQU8sQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFTO0lBQ3ZDLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUF5RDtJQUU3RSxZQUNtQixZQUFZLEVBQUUsWUFBWSxFQUMxQixZQUFZLEVBQUUsZ0JBQWdCLEVBQy9DLE1BQU0sRUFBRSwyQkFBMkIsRUFXcEM7SUFFWSxLQUFLLENBQUMsaUJBQWlCLFNBQXNDLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUl6RjtJQUVZLElBQUksSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBRWpDO1lBTWEsYUFBYTtZQWdCYixxQkFBcUI7SUFrQjVCLGlCQUFpQixJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FFM0M7SUFFTSxtQkFBbUIsQ0FBQyxTQUFTLENBQUMsRUFBRSxpQkFBaUIsR0FBRyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FJNUU7Q0FDRiJ9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fee_provider.d.ts","sourceRoot":"","sources":["../../src/global_variable_builder/fee_provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"fee_provider.d.ts","sourceRoot":"","sources":["../../src/global_variable_builder/fee_provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAI9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAKvE;;GAEG;AACH,qBAAa,eAAgB,YAAW,WAAW;IAY/C,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAZ/B,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,oBAAoB,CAAiC;IAC7D,OAAO,CAAC,WAAW,CAA6B;IAEhD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAC9C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAyD;IAE7E,YACmB,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,gBAAgB,EAC/C,MAAM,EAAE,2BAA2B,EAWpC;IAEY,KAAK,CAAC,iBAAiB,SAAsC,GAAG,OAAO,CAAC,IAAI,CAAC,CAIzF;IAEY,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjC;YAMa,aAAa;YAgBb,qBAAqB;IAkB5B,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAE3C;IAEM,mBAAmB,CAAC,SAAS,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAI5E;CACF"}
|
|
@@ -1,31 +1,62 @@
|
|
|
1
1
|
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
2
2
|
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
3
5
|
import { getNextL1SlotTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
4
6
|
import { GasFees, ManaUsageEstimate } from '@aztec/stdlib/gas';
|
|
5
7
|
import { FeePredictor } from './fee_predictor.js';
|
|
6
|
-
/**
|
|
8
|
+
/** Default interval for the background L1 refresh loop, well below L1's block time. */ const DEFAULT_REFRESH_POLLING_INTERVAL_MS = 1000;
|
|
9
|
+
/**
|
|
10
|
+
* Provides current and predicted fee information based on on-chain state.
|
|
11
|
+
*/ export class FeeProviderImpl {
|
|
7
12
|
dateProvider;
|
|
8
13
|
publicClient;
|
|
9
14
|
currentMinFees;
|
|
10
15
|
currentL1BlockNumber;
|
|
16
|
+
refreshLoop;
|
|
11
17
|
rollupContract;
|
|
12
18
|
feePredictor;
|
|
13
19
|
ethereumSlotDuration;
|
|
14
20
|
l1GenesisTime;
|
|
21
|
+
log;
|
|
15
22
|
constructor(dateProvider, publicClient, config){
|
|
16
23
|
this.dateProvider = dateProvider;
|
|
17
24
|
this.publicClient = publicClient;
|
|
18
|
-
this.currentMinFees =
|
|
25
|
+
this.currentMinFees = new GasFees(0, 0);
|
|
19
26
|
this.currentL1BlockNumber = undefined;
|
|
27
|
+
this.log = createLogger('sequencer-client:fee-provider');
|
|
20
28
|
this.ethereumSlotDuration = config.ethereumSlotDuration;
|
|
21
29
|
this.l1GenesisTime = config.l1GenesisTime;
|
|
22
30
|
this.rollupContract = new RollupContract(this.publicClient, config.rollupAddress);
|
|
23
|
-
this.feePredictor = new FeePredictor(this.rollupContract, this.
|
|
31
|
+
this.feePredictor = new FeePredictor(this.rollupContract, this.dateProvider, {
|
|
24
32
|
slotDuration: config.slotDuration,
|
|
25
33
|
l1GenesisTime: config.l1GenesisTime,
|
|
26
34
|
ethereumSlotDuration: config.ethereumSlotDuration
|
|
27
35
|
});
|
|
28
36
|
}
|
|
37
|
+
async start(pollingIntervalMs = DEFAULT_REFRESH_POLLING_INTERVAL_MS) {
|
|
38
|
+
await this.refreshFromL1();
|
|
39
|
+
this.refreshLoop = new RunningPromise(()=>this.refreshFromL1(), this.log, pollingIntervalMs);
|
|
40
|
+
this.refreshLoop.start();
|
|
41
|
+
}
|
|
42
|
+
async stop() {
|
|
43
|
+
await this.refreshLoop?.stop();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Checks the current L1 block number and, if it has advanced, refreshes both the current and
|
|
47
|
+
* predicted min fees for that block.
|
|
48
|
+
*/ async refreshFromL1() {
|
|
49
|
+
const blockNumber = await this.publicClient.getBlockNumber({
|
|
50
|
+
cacheTime: 0
|
|
51
|
+
});
|
|
52
|
+
if (this.currentL1BlockNumber !== undefined && blockNumber <= this.currentL1BlockNumber) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const currentMinFees = await this.computeCurrentMinFees();
|
|
56
|
+
await this.feePredictor.refreshState(blockNumber);
|
|
57
|
+
this.currentMinFees = currentMinFees;
|
|
58
|
+
this.currentL1BlockNumber = blockNumber;
|
|
59
|
+
}
|
|
29
60
|
/**
|
|
30
61
|
* Computes the "current" min fees, e.g., the price that you currently should pay to get include in the next block
|
|
31
62
|
* @returns Min fees for the next block
|
|
@@ -42,39 +73,15 @@ import { FeePredictor } from './fee_predictor.js';
|
|
|
42
73
|
const timestamp = earliestTimestamp > nextEthTimestamp ? earliestTimestamp : nextEthTimestamp;
|
|
43
74
|
return new GasFees(0, await this.rollupContract.getManaMinFeeAt(timestamp, true));
|
|
44
75
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const blockNumber = await this.publicClient.getBlockNumber({
|
|
48
|
-
cacheTime: 0
|
|
49
|
-
});
|
|
50
|
-
// If the L1 block number has changed then chain a new promise to get the current min fees.
|
|
51
|
-
// We chain off the previous promise's settlement (via a swallowing catch) rather than its
|
|
52
|
-
// fulfillment, so a prior rejection does not short-circuit the new computation. If the new
|
|
53
|
-
// computation fails (e.g. a transient L1 RPC error), reset the cached block number so the
|
|
54
|
-
// next call recomputes instead of permanently replaying the rejected promise — otherwise a
|
|
55
|
-
// single transient failure would wedge fee estimation until the next L1 block arrives. Only
|
|
56
|
-
// clear it if it still points at the block this attempt was for, so a stale rejection from an
|
|
57
|
-
// older block cannot wipe a marker a newer call already advanced (which would also defeat the
|
|
58
|
-
// monotonic block-number guard).
|
|
59
|
-
if (this.currentL1BlockNumber === undefined || blockNumber > this.currentL1BlockNumber) {
|
|
60
|
-
this.currentL1BlockNumber = blockNumber;
|
|
61
|
-
this.currentMinFees = this.currentMinFees.catch(()=>undefined).then(()=>this.computeCurrentMinFees().catch((err)=>{
|
|
62
|
-
if (this.currentL1BlockNumber === blockNumber) {
|
|
63
|
-
this.currentL1BlockNumber = undefined;
|
|
64
|
-
}
|
|
65
|
-
throw err;
|
|
66
|
-
}));
|
|
67
|
-
}
|
|
68
|
-
return this.currentMinFees;
|
|
76
|
+
getCurrentMinFees() {
|
|
77
|
+
return Promise.resolve(this.currentMinFees);
|
|
69
78
|
}
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
]);
|
|
75
|
-
return [
|
|
79
|
+
getPredictedMinFees(manaUsage) {
|
|
80
|
+
const currentMinFees = this.currentMinFees;
|
|
81
|
+
const predictedMinFees = this.feePredictor.getPredictedMinFees(manaUsage ?? ManaUsageEstimate.Target);
|
|
82
|
+
return Promise.resolve([
|
|
76
83
|
currentMinFees,
|
|
77
84
|
...predictedMinFees
|
|
78
|
-
];
|
|
85
|
+
]);
|
|
79
86
|
}
|
|
80
87
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/sequencer-client",
|
|
3
|
-
"version": "5.3.0-nightly.
|
|
3
|
+
"version": "5.3.0-nightly.20260822",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -27,37 +27,37 @@
|
|
|
27
27
|
"test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --config jest.integration.config.json"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@aztec/aztec.js": "5.3.0-nightly.
|
|
31
|
-
"@aztec/bb-prover": "5.3.0-nightly.
|
|
32
|
-
"@aztec/blob-client": "5.3.0-nightly.
|
|
33
|
-
"@aztec/blob-lib": "5.3.0-nightly.
|
|
34
|
-
"@aztec/constants": "5.3.0-nightly.
|
|
35
|
-
"@aztec/epoch-cache": "5.3.0-nightly.
|
|
36
|
-
"@aztec/ethereum": "5.3.0-nightly.
|
|
37
|
-
"@aztec/foundation": "5.3.0-nightly.
|
|
38
|
-
"@aztec/l1-artifacts": "5.3.0-nightly.
|
|
39
|
-
"@aztec/node-keystore": "5.3.0-nightly.
|
|
40
|
-
"@aztec/noir-acvm_js": "5.3.0-nightly.
|
|
41
|
-
"@aztec/noir-contracts.js": "5.3.0-nightly.
|
|
42
|
-
"@aztec/noir-protocol-circuits-types": "5.3.0-nightly.
|
|
43
|
-
"@aztec/noir-types": "5.3.0-nightly.
|
|
44
|
-
"@aztec/p2p": "5.3.0-nightly.
|
|
45
|
-
"@aztec/protocol-contracts": "5.3.0-nightly.
|
|
46
|
-
"@aztec/prover-client": "5.3.0-nightly.
|
|
47
|
-
"@aztec/simulator": "5.3.0-nightly.
|
|
48
|
-
"@aztec/slasher": "5.3.0-nightly.
|
|
49
|
-
"@aztec/stdlib": "5.3.0-nightly.
|
|
50
|
-
"@aztec/telemetry-client": "5.3.0-nightly.
|
|
51
|
-
"@aztec/validator-client": "5.3.0-nightly.
|
|
52
|
-
"@aztec/validator-ha-signer": "5.3.0-nightly.
|
|
53
|
-
"@aztec/world-state": "5.3.0-nightly.
|
|
30
|
+
"@aztec/aztec.js": "5.3.0-nightly.20260822",
|
|
31
|
+
"@aztec/bb-prover": "5.3.0-nightly.20260822",
|
|
32
|
+
"@aztec/blob-client": "5.3.0-nightly.20260822",
|
|
33
|
+
"@aztec/blob-lib": "5.3.0-nightly.20260822",
|
|
34
|
+
"@aztec/constants": "5.3.0-nightly.20260822",
|
|
35
|
+
"@aztec/epoch-cache": "5.3.0-nightly.20260822",
|
|
36
|
+
"@aztec/ethereum": "5.3.0-nightly.20260822",
|
|
37
|
+
"@aztec/foundation": "5.3.0-nightly.20260822",
|
|
38
|
+
"@aztec/l1-artifacts": "5.3.0-nightly.20260822",
|
|
39
|
+
"@aztec/node-keystore": "5.3.0-nightly.20260822",
|
|
40
|
+
"@aztec/noir-acvm_js": "5.3.0-nightly.20260822",
|
|
41
|
+
"@aztec/noir-contracts.js": "5.3.0-nightly.20260822",
|
|
42
|
+
"@aztec/noir-protocol-circuits-types": "5.3.0-nightly.20260822",
|
|
43
|
+
"@aztec/noir-types": "5.3.0-nightly.20260822",
|
|
44
|
+
"@aztec/p2p": "5.3.0-nightly.20260822",
|
|
45
|
+
"@aztec/protocol-contracts": "5.3.0-nightly.20260822",
|
|
46
|
+
"@aztec/prover-client": "5.3.0-nightly.20260822",
|
|
47
|
+
"@aztec/simulator": "5.3.0-nightly.20260822",
|
|
48
|
+
"@aztec/slasher": "5.3.0-nightly.20260822",
|
|
49
|
+
"@aztec/stdlib": "5.3.0-nightly.20260822",
|
|
50
|
+
"@aztec/telemetry-client": "5.3.0-nightly.20260822",
|
|
51
|
+
"@aztec/validator-client": "5.3.0-nightly.20260822",
|
|
52
|
+
"@aztec/validator-ha-signer": "5.3.0-nightly.20260822",
|
|
53
|
+
"@aztec/world-state": "5.3.0-nightly.20260822",
|
|
54
54
|
"lodash.chunk": "^4.2.0",
|
|
55
55
|
"tslib": "^2.4.0",
|
|
56
56
|
"viem": "npm:@aztec/viem@2.38.2"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@aztec/archiver": "5.3.0-nightly.
|
|
60
|
-
"@aztec/kv-store": "5.3.0-nightly.
|
|
59
|
+
"@aztec/archiver": "5.3.0-nightly.20260822",
|
|
60
|
+
"@aztec/kv-store": "5.3.0-nightly.20260822",
|
|
61
61
|
"@electric-sql/pglite": "^0.3.14",
|
|
62
62
|
"@jest/globals": "^30.0.0",
|
|
63
63
|
"@types/jest": "^30.0.0",
|
|
@@ -28,12 +28,10 @@ type FeeOracleState = {
|
|
|
28
28
|
/**
|
|
29
29
|
* Predicts min fees for LAG upcoming slots based on the L1 oracle state.
|
|
30
30
|
* A new oracle update can activate at startSlot + LAG, so only the first LAG entries
|
|
31
|
-
* are guaranteed stable.
|
|
32
|
-
* for each mana usage estimate.
|
|
31
|
+
* are guaranteed stable.
|
|
33
32
|
*/
|
|
34
33
|
export class FeePredictor {
|
|
35
|
-
private cachedState:
|
|
36
|
-
private cachedL1BlockNumber: bigint | undefined;
|
|
34
|
+
private cachedState: FeeOracleState | undefined;
|
|
37
35
|
|
|
38
36
|
private readonly slotDuration: number;
|
|
39
37
|
private readonly l1GenesisTime: bigint;
|
|
@@ -41,7 +39,6 @@ export class FeePredictor {
|
|
|
41
39
|
|
|
42
40
|
constructor(
|
|
43
41
|
private readonly rollupContract: RollupContract,
|
|
44
|
-
private readonly publicClient: { getBlockNumber: (opts?: { cacheTime?: number }) => Promise<bigint> },
|
|
45
42
|
private readonly dateProvider: DateProvider,
|
|
46
43
|
config: { slotDuration: number; l1GenesisTime: bigint; ethereumSlotDuration: number },
|
|
47
44
|
) {
|
|
@@ -50,30 +47,27 @@ export class FeePredictor {
|
|
|
50
47
|
this.ethereumSlotDuration = config.ethereumSlotDuration;
|
|
51
48
|
}
|
|
52
49
|
|
|
53
|
-
/** Returns predicted min fees for each slot in the prediction window. */
|
|
54
|
-
|
|
55
|
-
const state =
|
|
50
|
+
/** Returns predicted min fees for each slot in the prediction window, from the cached state. */
|
|
51
|
+
getPredictedMinFees(manaUsage: ManaUsageEstimate): GasFees[] {
|
|
52
|
+
const state = this.getState();
|
|
53
|
+
if (state === undefined) {
|
|
54
|
+
throw new Error('FeePredictor.refreshState() must be called before getPredictedMinFees()');
|
|
55
|
+
}
|
|
56
56
|
return this.computePredictions(state, manaUsage);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
/**
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
this.cachedL1BlockNumber = undefined;
|
|
72
|
-
}
|
|
73
|
-
throw err;
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
return this.cachedState!;
|
|
59
|
+
/** Returns whatever rollup state is currently cached, or undefined if refreshState() has never been called. */
|
|
60
|
+
getState(): FeeOracleState | undefined {
|
|
61
|
+
return this.cachedState;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Fetches and caches rollup state for the given L1 block.
|
|
66
|
+
*/
|
|
67
|
+
async refreshState(blockNumber: bigint): Promise<FeeOracleState> {
|
|
68
|
+
const state = await this.fetchState(blockNumber);
|
|
69
|
+
this.cachedState = state;
|
|
70
|
+
return state;
|
|
77
71
|
}
|
|
78
72
|
|
|
79
73
|
private async fetchState(blockNumber: bigint): Promise<FeeOracleState> {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
2
2
|
import type { ViemPublicClient } from '@aztec/ethereum/types';
|
|
3
3
|
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
4
|
+
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
5
|
+
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
4
6
|
import type { DateProvider } from '@aztec/foundation/timer';
|
|
5
7
|
import { getNextL1SlotTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
6
8
|
import { GasFees, ManaUsageEstimate } from '@aztec/stdlib/gas';
|
|
@@ -9,15 +11,22 @@ import type { FeeProvider } from '@aztec/stdlib/tx';
|
|
|
9
11
|
import { FeePredictor } from './fee_predictor.js';
|
|
10
12
|
import type { GlobalVariableBuilderConfig } from './global_builder.js';
|
|
11
13
|
|
|
12
|
-
/**
|
|
14
|
+
/** Default interval for the background L1 refresh loop, well below L1's block time. */
|
|
15
|
+
const DEFAULT_REFRESH_POLLING_INTERVAL_MS = 1000;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Provides current and predicted fee information based on on-chain state.
|
|
19
|
+
*/
|
|
13
20
|
export class FeeProviderImpl implements FeeProvider {
|
|
14
|
-
private currentMinFees
|
|
21
|
+
private currentMinFees = new GasFees(0, 0);
|
|
15
22
|
private currentL1BlockNumber: bigint | undefined = undefined;
|
|
23
|
+
private refreshLoop: RunningPromise | undefined;
|
|
16
24
|
|
|
17
25
|
private readonly rollupContract: RollupContract;
|
|
18
26
|
private readonly feePredictor: FeePredictor;
|
|
19
27
|
private readonly ethereumSlotDuration: number;
|
|
20
28
|
private readonly l1GenesisTime: bigint;
|
|
29
|
+
private readonly log: Logger = createLogger('sequencer-client:fee-provider');
|
|
21
30
|
|
|
22
31
|
constructor(
|
|
23
32
|
private readonly dateProvider: DateProvider,
|
|
@@ -28,13 +37,39 @@ export class FeeProviderImpl implements FeeProvider {
|
|
|
28
37
|
this.l1GenesisTime = config.l1GenesisTime;
|
|
29
38
|
|
|
30
39
|
this.rollupContract = new RollupContract(this.publicClient, config.rollupAddress);
|
|
31
|
-
this.feePredictor = new FeePredictor(this.rollupContract, this.
|
|
40
|
+
this.feePredictor = new FeePredictor(this.rollupContract, this.dateProvider, {
|
|
32
41
|
slotDuration: config.slotDuration,
|
|
33
42
|
l1GenesisTime: config.l1GenesisTime,
|
|
34
43
|
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
35
44
|
});
|
|
36
45
|
}
|
|
37
46
|
|
|
47
|
+
public async start(pollingIntervalMs = DEFAULT_REFRESH_POLLING_INTERVAL_MS): Promise<void> {
|
|
48
|
+
await this.refreshFromL1();
|
|
49
|
+
this.refreshLoop = new RunningPromise(() => this.refreshFromL1(), this.log, pollingIntervalMs);
|
|
50
|
+
this.refreshLoop.start();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public async stop(): Promise<void> {
|
|
54
|
+
await this.refreshLoop?.stop();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Checks the current L1 block number and, if it has advanced, refreshes both the current and
|
|
59
|
+
* predicted min fees for that block.
|
|
60
|
+
*/
|
|
61
|
+
private async refreshFromL1(): Promise<void> {
|
|
62
|
+
const blockNumber = await this.publicClient.getBlockNumber({ cacheTime: 0 });
|
|
63
|
+
if (this.currentL1BlockNumber !== undefined && blockNumber <= this.currentL1BlockNumber) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const currentMinFees = await this.computeCurrentMinFees();
|
|
68
|
+
await this.feePredictor.refreshState(blockNumber);
|
|
69
|
+
this.currentMinFees = currentMinFees;
|
|
70
|
+
this.currentL1BlockNumber = blockNumber;
|
|
71
|
+
}
|
|
72
|
+
|
|
38
73
|
/**
|
|
39
74
|
* Computes the "current" min fees, e.g., the price that you currently should pay to get include in the next block
|
|
40
75
|
* @returns Min fees for the next block
|
|
@@ -57,41 +92,13 @@ export class FeeProviderImpl implements FeeProvider {
|
|
|
57
92
|
return new GasFees(0, await this.rollupContract.getManaMinFeeAt(timestamp, true));
|
|
58
93
|
}
|
|
59
94
|
|
|
60
|
-
public
|
|
61
|
-
|
|
62
|
-
const blockNumber = await this.publicClient.getBlockNumber({ cacheTime: 0 });
|
|
63
|
-
|
|
64
|
-
// If the L1 block number has changed then chain a new promise to get the current min fees.
|
|
65
|
-
// We chain off the previous promise's settlement (via a swallowing catch) rather than its
|
|
66
|
-
// fulfillment, so a prior rejection does not short-circuit the new computation. If the new
|
|
67
|
-
// computation fails (e.g. a transient L1 RPC error), reset the cached block number so the
|
|
68
|
-
// next call recomputes instead of permanently replaying the rejected promise — otherwise a
|
|
69
|
-
// single transient failure would wedge fee estimation until the next L1 block arrives. Only
|
|
70
|
-
// clear it if it still points at the block this attempt was for, so a stale rejection from an
|
|
71
|
-
// older block cannot wipe a marker a newer call already advanced (which would also defeat the
|
|
72
|
-
// monotonic block-number guard).
|
|
73
|
-
if (this.currentL1BlockNumber === undefined || blockNumber > this.currentL1BlockNumber) {
|
|
74
|
-
this.currentL1BlockNumber = blockNumber;
|
|
75
|
-
this.currentMinFees = this.currentMinFees
|
|
76
|
-
.catch(() => undefined)
|
|
77
|
-
.then(() =>
|
|
78
|
-
this.computeCurrentMinFees().catch(err => {
|
|
79
|
-
if (this.currentL1BlockNumber === blockNumber) {
|
|
80
|
-
this.currentL1BlockNumber = undefined;
|
|
81
|
-
}
|
|
82
|
-
throw err;
|
|
83
|
-
}),
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
return this.currentMinFees;
|
|
95
|
+
public getCurrentMinFees(): Promise<GasFees> {
|
|
96
|
+
return Promise.resolve(this.currentMinFees);
|
|
87
97
|
}
|
|
88
98
|
|
|
89
|
-
public
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
]);
|
|
94
|
-
|
|
95
|
-
return [currentMinFees, ...predictedMinFees];
|
|
99
|
+
public getPredictedMinFees(manaUsage?: ManaUsageEstimate): Promise<GasFees[]> {
|
|
100
|
+
const currentMinFees = this.currentMinFees;
|
|
101
|
+
const predictedMinFees = this.feePredictor.getPredictedMinFees(manaUsage ?? ManaUsageEstimate.Target);
|
|
102
|
+
return Promise.resolve([currentMinFees, ...predictedMinFees]);
|
|
96
103
|
}
|
|
97
104
|
}
|