@aztec/ethereum 0.0.1-commit.6c91f13 → 0.0.1-commit.96bb3f7
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/contracts/fee_asset_handler.d.ts +6 -5
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.js +9 -9
- package/dest/contracts/governance_proposer.js +382 -8
- 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/outbox.d.ts +41 -0
- package/dest/contracts/outbox.d.ts.map +1 -0
- package/dest/contracts/outbox.js +86 -0
- package/dest/contracts/rollup.d.ts +128 -95
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +602 -127
- package/dest/deploy_aztec_l1_contracts.d.ts +10 -2
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +60 -11
- package/dest/l1_artifacts.d.ts +3512 -1082
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_tx_utils/fee-strategies/index.d.ts +3 -2
- package/dest/l1_tx_utils/fee-strategies/index.d.ts.map +1 -1
- package/dest/l1_tx_utils/fee-strategies/index.js +2 -1
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts +2 -12
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts.map +1 -1
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +35 -17
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts +2 -11
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts.map +1 -1
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +36 -18
- package/dest/l1_tx_utils/fee-strategies/types.d.ts +14 -27
- package/dest/l1_tx_utils/fee-strategies/types.d.ts.map +1 -1
- package/dest/l1_tx_utils/fee-strategies/types.js +0 -21
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +2 -2
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_fee_analyzer.js +3 -3
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +1 -5
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +14 -51
- package/dest/queries.js +2 -2
- package/dest/test/chain_monitor.js +1 -2
- package/dest/test/rollup_cheat_codes.d.ts +2 -1
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +9 -1
- package/package.json +5 -5
- package/src/contracts/fee_asset_handler.ts +8 -7
- package/src/contracts/index.ts +1 -0
- package/src/contracts/outbox.ts +98 -0
- package/src/contracts/rollup.ts +240 -92
- package/src/deploy_aztec_l1_contracts.ts +61 -13
- package/src/l1_tx_utils/fee-strategies/index.ts +1 -1
- package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +45 -41
- package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +48 -44
- package/src/l1_tx_utils/fee-strategies/types.ts +14 -46
- package/src/l1_tx_utils/l1_fee_analyzer.ts +2 -3
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +20 -59
- package/src/queries.ts +2 -2
- package/src/test/chain_monitor.ts +1 -1
- package/src/test/rollup_cheat_codes.ts +10 -1
|
@@ -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);
|
|
@@ -513,10 +563,8 @@ export const deployRollupForUpgrade = async (
|
|
|
513
563
|
| 'zkPassportArgs'
|
|
514
564
|
>,
|
|
515
565
|
) => {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
// Relative location of l1-contracts in monorepo or docker image.
|
|
519
|
-
const l1ContractsPath = resolve(currentDir, '..', '..', '..', 'l1-contracts');
|
|
566
|
+
// Use foundry-artifacts from l1-artifacts package
|
|
567
|
+
const l1ContractsPath = prepareL1ContractsForDeployment();
|
|
520
568
|
|
|
521
569
|
const FORGE_SCRIPT = 'script/deploy/DeployRollupForUpgrade.s.sol';
|
|
522
570
|
await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
@@ -4,13 +4,13 @@ import type { PriorityFeeStrategy } from './types.js';
|
|
|
4
4
|
|
|
5
5
|
export {
|
|
6
6
|
HISTORICAL_BLOCK_COUNT,
|
|
7
|
-
executeStrategy,
|
|
8
7
|
type PriorityFeeStrategy,
|
|
9
8
|
type PriorityFeeStrategyContext,
|
|
10
9
|
type PriorityFeeStrategyResult,
|
|
11
10
|
} from './types.js';
|
|
12
11
|
|
|
13
12
|
export { P75AllTxsPriorityFeeStrategy } from './p75_competitive.js';
|
|
13
|
+
export { P75BlobTxsOnlyPriorityFeeStrategy } from './p75_competitive_blob_txs_only.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Default list of priority fee strategies to analyze.
|
|
@@ -12,50 +12,54 @@ import {
|
|
|
12
12
|
type PriorityFeeStrategyResult,
|
|
13
13
|
} from './types.js';
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* Type for the promises required by the competitive strategy
|
|
17
|
-
*/
|
|
18
|
-
type P75AllTxsStrategyPromises = {
|
|
19
|
-
networkEstimate: Promise<bigint>;
|
|
20
|
-
pendingBlock: Promise<Awaited<ReturnType<ViemClient['getBlock']>> | null>;
|
|
21
|
-
feeHistory: Promise<Awaited<ReturnType<ViemClient['getFeeHistory']>> | null>;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
15
|
/**
|
|
25
16
|
* Our current competitive priority fee strategy.
|
|
26
17
|
* Analyzes p75 of pending transactions and 5-block fee history to determine a competitive priority fee.
|
|
27
18
|
* Falls back to network estimate if data is unavailable.
|
|
28
19
|
*/
|
|
29
|
-
export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy
|
|
20
|
+
export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy = {
|
|
30
21
|
name: 'Competitive (P75 + History) - CURRENT',
|
|
31
22
|
id: 'p75_pending_txs_and_history_all_txs',
|
|
32
23
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
24
|
+
async execute(client: ViemClient, context: PriorityFeeStrategyContext): Promise<PriorityFeeStrategyResult> {
|
|
25
|
+
const { isBlobTx, logger } = context;
|
|
26
|
+
|
|
27
|
+
// Fire all RPC calls in parallel
|
|
28
|
+
const [latestBlockResult, blobBaseFeeResult, networkEstimateResult, pendingBlockResult, feeHistoryResult] =
|
|
29
|
+
await Promise.allSettled([
|
|
30
|
+
client.getBlock({ blockTag: 'latest' }),
|
|
31
|
+
isBlobTx ? client.getBlobBaseFee() : Promise.resolve(undefined),
|
|
32
|
+
client.estimateMaxPriorityFeePerGas().catch(() => 0n),
|
|
33
|
+
client.getBlock({ blockTag: 'pending', includeTransactions: true }).catch(() => null),
|
|
34
|
+
client
|
|
35
|
+
.getFeeHistory({
|
|
36
|
+
blockCount: HISTORICAL_BLOCK_COUNT,
|
|
37
|
+
rewardPercentiles: [75],
|
|
38
|
+
blockTag: 'latest',
|
|
39
|
+
})
|
|
40
|
+
.catch(() => null),
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
// Extract latest block
|
|
44
|
+
if (latestBlockResult.status === 'rejected') {
|
|
45
|
+
throw new Error(`Failed to get latest block: ${latestBlockResult.reason}`);
|
|
46
|
+
}
|
|
47
|
+
const latestBlock = latestBlockResult.value;
|
|
48
|
+
|
|
49
|
+
// Extract blob base fee (only for blob txs)
|
|
50
|
+
let blobBaseFee: bigint | undefined;
|
|
51
|
+
if (isBlobTx) {
|
|
52
|
+
if (blobBaseFeeResult.status === 'fulfilled' && typeof blobBaseFeeResult.value === 'bigint') {
|
|
53
|
+
blobBaseFee = blobBaseFeeResult.value;
|
|
54
|
+
} else {
|
|
55
|
+
logger?.warn('Failed to get L1 blob base fee');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
54
58
|
|
|
55
|
-
// Extract network estimate
|
|
59
|
+
// Extract network estimate
|
|
56
60
|
const networkEstimate =
|
|
57
|
-
|
|
58
|
-
?
|
|
61
|
+
networkEstimateResult.status === 'fulfilled' && typeof networkEstimateResult.value === 'bigint'
|
|
62
|
+
? networkEstimateResult.value
|
|
59
63
|
: 0n;
|
|
60
64
|
|
|
61
65
|
let competitiveFee = networkEstimate;
|
|
@@ -63,8 +67,8 @@ export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStrategy
|
|
|
63
67
|
networkEstimateGwei: formatGwei(networkEstimate),
|
|
64
68
|
};
|
|
65
69
|
|
|
66
|
-
// Extract pending block
|
|
67
|
-
const pendingBlock =
|
|
70
|
+
// Extract pending block
|
|
71
|
+
const pendingBlock = pendingBlockResult.status === 'fulfilled' ? pendingBlockResult.value : null;
|
|
68
72
|
|
|
69
73
|
// Analyze pending block transactions
|
|
70
74
|
if (pendingBlock?.transactions && pendingBlock.transactions.length > 0) {
|
|
@@ -73,9 +77,7 @@ export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStrategy
|
|
|
73
77
|
if (typeof tx === 'string') {
|
|
74
78
|
return 0n;
|
|
75
79
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return fee;
|
|
80
|
+
return tx.maxPriorityFeePerGas || 0n;
|
|
79
81
|
})
|
|
80
82
|
.filter((fee: bigint) => fee > 0n);
|
|
81
83
|
|
|
@@ -97,8 +99,8 @@ export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStrategy
|
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
// Extract fee history
|
|
101
|
-
const feeHistory =
|
|
102
|
+
// Extract fee history
|
|
103
|
+
const feeHistory = feeHistoryResult.status === 'fulfilled' ? feeHistoryResult.value : null;
|
|
102
104
|
|
|
103
105
|
// Analyze fee history
|
|
104
106
|
if (feeHistory?.reward && feeHistory.reward.length > 0) {
|
|
@@ -153,6 +155,8 @@ export const P75AllTxsPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStrategy
|
|
|
153
155
|
|
|
154
156
|
return {
|
|
155
157
|
priorityFee: competitiveFee,
|
|
158
|
+
latestBlock,
|
|
159
|
+
blobBaseFee,
|
|
156
160
|
debugInfo,
|
|
157
161
|
};
|
|
158
162
|
},
|
|
@@ -12,15 +12,6 @@ import {
|
|
|
12
12
|
type PriorityFeeStrategyResult,
|
|
13
13
|
} from './types.js';
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* Type for the promises required by the competitive strategy
|
|
17
|
-
*/
|
|
18
|
-
type P75AllTxsStrategyPromises = {
|
|
19
|
-
networkEstimate: Promise<bigint>;
|
|
20
|
-
pendingBlock: Promise<Awaited<ReturnType<ViemClient['getBlock']>> | null>;
|
|
21
|
-
feeHistory: Promise<Awaited<ReturnType<ViemClient['getFeeHistory']>> | null>;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
15
|
/**
|
|
25
16
|
* Fetches historical blocks and calculates reward percentiles for blob transactions only.
|
|
26
17
|
* Returns data in the same format as getFeeHistory for easy drop-in replacement.
|
|
@@ -114,38 +105,51 @@ export async function getBlobPriorityFeeHistory(
|
|
|
114
105
|
* Analyzes p75 of pending transactions and 5-block fee history to determine a competitive priority fee.
|
|
115
106
|
* Falls back to network estimate if data is unavailable.
|
|
116
107
|
*/
|
|
117
|
-
export const P75BlobTxsOnlyPriorityFeeStrategy: PriorityFeeStrategy
|
|
108
|
+
export const P75BlobTxsOnlyPriorityFeeStrategy: PriorityFeeStrategy = {
|
|
118
109
|
name: 'Competitive (P75 + History) - Blob Txs Only',
|
|
119
110
|
id: 'p75_pending_txs_and_history_blob_txs_only',
|
|
120
111
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
:
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
112
|
+
async execute(client: ViemClient, context: PriorityFeeStrategyContext): Promise<PriorityFeeStrategyResult> {
|
|
113
|
+
const { isBlobTx, logger } = context;
|
|
114
|
+
|
|
115
|
+
// Fire all RPC calls in parallel
|
|
116
|
+
const [latestBlockResult, blobBaseFeeResult, networkEstimateResult, pendingBlockResult, feeHistoryResult] =
|
|
117
|
+
await Promise.allSettled([
|
|
118
|
+
client.getBlock({ blockTag: 'latest' }),
|
|
119
|
+
isBlobTx ? client.getBlobBaseFee() : Promise.resolve(undefined),
|
|
120
|
+
client.estimateMaxPriorityFeePerGas().catch(() => 0n),
|
|
121
|
+
client.getBlock({ blockTag: 'pending', includeTransactions: true }).catch(() => null),
|
|
122
|
+
isBlobTx
|
|
123
|
+
? getBlobPriorityFeeHistory(client, HISTORICAL_BLOCK_COUNT, [75])
|
|
124
|
+
: client
|
|
125
|
+
.getFeeHistory({
|
|
126
|
+
blockCount: HISTORICAL_BLOCK_COUNT,
|
|
127
|
+
rewardPercentiles: [75],
|
|
128
|
+
blockTag: 'latest',
|
|
129
|
+
})
|
|
130
|
+
.catch(() => null),
|
|
131
|
+
]);
|
|
132
|
+
|
|
133
|
+
// Extract latest block (required)
|
|
134
|
+
if (latestBlockResult.status === 'rejected') {
|
|
135
|
+
throw new Error(`Failed to get latest block: ${latestBlockResult.reason}`);
|
|
136
|
+
}
|
|
137
|
+
const latestBlock = latestBlockResult.value;
|
|
138
|
+
|
|
139
|
+
// Extract blob base fee (only for blob txs)
|
|
140
|
+
let blobBaseFee: bigint | undefined;
|
|
141
|
+
if (isBlobTx) {
|
|
142
|
+
if (blobBaseFeeResult.status === 'fulfilled' && typeof blobBaseFeeResult.value === 'bigint') {
|
|
143
|
+
blobBaseFee = blobBaseFeeResult.value;
|
|
144
|
+
} else {
|
|
145
|
+
logger?.warn('Failed to get L1 blob base fee');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
144
148
|
|
|
145
|
-
// Extract network estimate
|
|
149
|
+
// Extract network estimate
|
|
146
150
|
const networkEstimate =
|
|
147
|
-
|
|
148
|
-
?
|
|
151
|
+
networkEstimateResult.status === 'fulfilled' && typeof networkEstimateResult.value === 'bigint'
|
|
152
|
+
? networkEstimateResult.value
|
|
149
153
|
: 0n;
|
|
150
154
|
|
|
151
155
|
let competitiveFee = networkEstimate;
|
|
@@ -153,8 +157,8 @@ export const P75BlobTxsOnlyPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStr
|
|
|
153
157
|
networkEstimateGwei: formatGwei(networkEstimate),
|
|
154
158
|
};
|
|
155
159
|
|
|
156
|
-
// Extract pending block
|
|
157
|
-
const pendingBlock =
|
|
160
|
+
// Extract pending block
|
|
161
|
+
const pendingBlock = pendingBlockResult.status === 'fulfilled' ? pendingBlockResult.value : null;
|
|
158
162
|
|
|
159
163
|
// Analyze pending block transactions
|
|
160
164
|
if (pendingBlock?.transactions && pendingBlock.transactions.length > 0) {
|
|
@@ -163,14 +167,12 @@ export const P75BlobTxsOnlyPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStr
|
|
|
163
167
|
if (typeof tx === 'string') {
|
|
164
168
|
return 0n;
|
|
165
169
|
}
|
|
166
|
-
if (
|
|
170
|
+
if (isBlobTx) {
|
|
167
171
|
if (!isBlobTransaction(tx)) {
|
|
168
172
|
return 0n;
|
|
169
173
|
}
|
|
170
174
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return fee;
|
|
175
|
+
return tx.maxPriorityFeePerGas || 0n;
|
|
174
176
|
})
|
|
175
177
|
.filter((fee: bigint) => fee > 0n);
|
|
176
178
|
|
|
@@ -191,8 +193,8 @@ export const P75BlobTxsOnlyPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStr
|
|
|
191
193
|
}
|
|
192
194
|
}
|
|
193
195
|
|
|
194
|
-
// Extract fee history
|
|
195
|
-
const feeHistory =
|
|
196
|
+
// Extract fee history
|
|
197
|
+
const feeHistory = feeHistoryResult.status === 'fulfilled' ? feeHistoryResult.value : null;
|
|
196
198
|
|
|
197
199
|
// Analyze fee history
|
|
198
200
|
if (feeHistory?.reward && feeHistory.reward.length > 0) {
|
|
@@ -235,6 +237,8 @@ export const P75BlobTxsOnlyPriorityFeeStrategy: PriorityFeeStrategy<P75AllTxsStr
|
|
|
235
237
|
|
|
236
238
|
return {
|
|
237
239
|
priorityFee: competitiveFee,
|
|
240
|
+
latestBlock,
|
|
241
|
+
blobBaseFee,
|
|
238
242
|
debugInfo,
|
|
239
243
|
};
|
|
240
244
|
},
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Logger } from '@aztec/foundation/log';
|
|
2
2
|
|
|
3
|
+
import type { Block } from 'viem';
|
|
4
|
+
|
|
3
5
|
import type { ViemClient } from '../../types.js';
|
|
4
6
|
import type { L1TxUtilsConfig } from '../config.js';
|
|
5
7
|
|
|
@@ -14,12 +16,16 @@ export const HISTORICAL_BLOCK_COUNT = 5;
|
|
|
14
16
|
export interface PriorityFeeStrategyResult {
|
|
15
17
|
/** The calculated priority fee in wei */
|
|
16
18
|
priorityFee: bigint;
|
|
19
|
+
/** The latest block (fetched as part of the strategy) */
|
|
20
|
+
latestBlock: Block;
|
|
21
|
+
/** The blob base fee (only present for blob transactions) */
|
|
22
|
+
blobBaseFee?: bigint;
|
|
17
23
|
/** Optional debug info about how the fee was calculated */
|
|
18
24
|
debugInfo?: Record<string, string | number>;
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
/**
|
|
22
|
-
* Context passed to the strategy
|
|
28
|
+
* Context passed to the strategy function
|
|
23
29
|
*/
|
|
24
30
|
export interface PriorityFeeStrategyContext {
|
|
25
31
|
/** Gas configuration */
|
|
@@ -32,57 +38,19 @@ export interface PriorityFeeStrategyContext {
|
|
|
32
38
|
|
|
33
39
|
/**
|
|
34
40
|
* A strategy for calculating the priority fee for L1 transactions.
|
|
35
|
-
*
|
|
36
|
-
*
|
|
41
|
+
* The function handles all RPC calls and returns
|
|
42
|
+
* the priority fee, along with any block data needed by the caller.
|
|
37
43
|
*/
|
|
38
|
-
export
|
|
44
|
+
export type PriorityFeeStrategy = {
|
|
39
45
|
/** Human-readable name for logging */
|
|
40
46
|
name: string;
|
|
41
47
|
/** Unique identifier for metrics */
|
|
42
48
|
id: string;
|
|
43
49
|
/**
|
|
44
|
-
*
|
|
45
|
-
* These will be run in parallel with Promise.allSettled.
|
|
50
|
+
* Calculate the priority fee.
|
|
46
51
|
* @param client - The viem client to use for RPC calls
|
|
47
|
-
* @returns An object of promises keyed by name
|
|
48
|
-
*/
|
|
49
|
-
getRequiredPromises(client: ViemClient, opts: Partial<PriorityFeeStrategyContext>): TPromises;
|
|
50
|
-
/**
|
|
51
|
-
* Calculate the priority fee based on the settled promise results.
|
|
52
|
-
* @param results - The settled results of the promises from getRequiredPromises
|
|
53
52
|
* @param context - Contains gas config, whether it's a blob tx, and logger
|
|
54
|
-
* @returns The calculated priority fee result
|
|
53
|
+
* @returns The calculated priority fee result including block data
|
|
55
54
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
context: PriorityFeeStrategyContext,
|
|
59
|
-
): PriorityFeeStrategyResult;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Helper function to execute a strategy's promises and calculate the result.
|
|
64
|
-
* This can be used by both L1FeeAnalyzer and ReadOnlyL1TxUtils.
|
|
65
|
-
* @param strategy - The strategy to execute
|
|
66
|
-
* @param client - The viem client to use for RPC calls
|
|
67
|
-
* @param context - The context for calculation
|
|
68
|
-
* @returns The strategy result
|
|
69
|
-
*/
|
|
70
|
-
export async function executeStrategy<TPromises extends Record<string, Promise<any>>>(
|
|
71
|
-
strategy: PriorityFeeStrategy<TPromises>,
|
|
72
|
-
client: ViemClient,
|
|
73
|
-
context: PriorityFeeStrategyContext,
|
|
74
|
-
): Promise<PriorityFeeStrategyResult> {
|
|
75
|
-
const promises = strategy.getRequiredPromises(client, { isBlobTx: context.isBlobTx });
|
|
76
|
-
const keys = Object.keys(promises) as Array<keyof TPromises>;
|
|
77
|
-
const promiseArray = keys.map(k => promises[k]);
|
|
78
|
-
|
|
79
|
-
const settledResults = await Promise.allSettled(promiseArray);
|
|
80
|
-
|
|
81
|
-
// Reconstruct the results object with the same keys, preserving the type mapping
|
|
82
|
-
const results = {} as { [K in keyof TPromises]: PromiseSettledResult<Awaited<TPromises[K]>> };
|
|
83
|
-
keys.forEach((key, index) => {
|
|
84
|
-
results[key] = settledResults[index] as PromiseSettledResult<Awaited<TPromises[typeof key]>>;
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
return strategy.calculate(results, context);
|
|
88
|
-
}
|
|
55
|
+
execute: (client: ViemClient, context: PriorityFeeStrategyContext) => Promise<PriorityFeeStrategyResult>;
|
|
56
|
+
};
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
DEFAULT_PRIORITY_FEE_STRATEGIES,
|
|
14
14
|
type PriorityFeeStrategy,
|
|
15
15
|
type PriorityFeeStrategyContext,
|
|
16
|
-
executeStrategy,
|
|
17
16
|
} from './fee-strategies/index.js';
|
|
18
17
|
import type { L1BlobInputs, L1TxRequest } from './types.js';
|
|
19
18
|
|
|
@@ -262,7 +261,7 @@ export class L1FeeAnalyzer {
|
|
|
262
261
|
|
|
263
262
|
/**
|
|
264
263
|
* Executes all configured strategies and returns their results.
|
|
265
|
-
* Each strategy
|
|
264
|
+
* Each strategy handles its own RPC calls internally.
|
|
266
265
|
* @param isBlobTx - Whether this is a blob transaction
|
|
267
266
|
* @returns Array of strategy results
|
|
268
267
|
*/
|
|
@@ -276,7 +275,7 @@ export class L1FeeAnalyzer {
|
|
|
276
275
|
|
|
277
276
|
for (const strategy of this.strategies) {
|
|
278
277
|
try {
|
|
279
|
-
const result = await
|
|
278
|
+
const result = await strategy.execute(this.client, context);
|
|
280
279
|
|
|
281
280
|
results.push({
|
|
282
281
|
strategyId: strategy.id,
|
|
@@ -84,63 +84,31 @@ export class ReadOnlyL1TxUtils {
|
|
|
84
84
|
): Promise<GasPrice> {
|
|
85
85
|
const gasConfig = merge(this.config, gasConfigOverrides);
|
|
86
86
|
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
// Execute strategy - it handles all RPC calls internally and returns everything we need
|
|
88
|
+
const strategyResult = await retry(
|
|
89
|
+
() =>
|
|
90
|
+
CurrentStrategy.execute(this.client, {
|
|
91
|
+
gasConfig,
|
|
92
|
+
isBlobTx,
|
|
93
|
+
logger: this.logger,
|
|
94
|
+
}),
|
|
95
|
+
'Executing priority fee strategy',
|
|
96
|
+
makeBackoff(times(2, () => 0)),
|
|
97
|
+
this.logger,
|
|
98
|
+
true,
|
|
92
99
|
);
|
|
93
100
|
|
|
94
|
-
|
|
95
|
-
if (isBlobTx) {
|
|
96
|
-
blobBaseFeePromise = this.tryTwice(() => this.client.getBlobBaseFee(), 'Getting blob base fee');
|
|
97
|
-
}
|
|
101
|
+
const { latestBlock, blobBaseFee, priorityFee: strategyPriorityFee } = strategyResult;
|
|
98
102
|
|
|
99
|
-
//
|
|
100
|
-
const
|
|
101
|
-
const strategyPromiseKeys = [];
|
|
102
|
-
const strategyPromisesArr = [];
|
|
103
|
-
for (const [key, promise] of Object.entries(strategyPromises)) {
|
|
104
|
-
strategyPromiseKeys.push(key);
|
|
105
|
-
strategyPromisesArr.push(this.tryTwice(() => promise, `Getting strategy data for ${key}`));
|
|
106
|
-
}
|
|
103
|
+
// Extract base fee from latest block
|
|
104
|
+
const baseFee = latestBlock.baseFeePerGas ?? 0n;
|
|
107
105
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
blobBaseFeePromise ?? Promise.resolve(0n),
|
|
111
|
-
...strategyPromisesArr,
|
|
112
|
-
]);
|
|
113
|
-
|
|
114
|
-
// Extract results
|
|
115
|
-
const baseFee =
|
|
116
|
-
latestBlockResult.status === 'fulfilled' &&
|
|
117
|
-
typeof latestBlockResult.value === 'object' &&
|
|
118
|
-
latestBlockResult.value.baseFeePerGas
|
|
119
|
-
? latestBlockResult.value.baseFeePerGas
|
|
120
|
-
: 0n;
|
|
121
|
-
|
|
122
|
-
// Get blob base fee if available
|
|
123
|
-
let blobBaseFee = 0n;
|
|
124
|
-
if (isBlobTx && blobBaseFeeResult.status === 'fulfilled' && typeof blobBaseFeeResult.value === 'bigint') {
|
|
125
|
-
blobBaseFee = blobBaseFeeResult.value;
|
|
126
|
-
} else if (isBlobTx) {
|
|
106
|
+
// Handle blob base fee
|
|
107
|
+
if (isBlobTx && blobBaseFee === undefined) {
|
|
127
108
|
this.logger?.warn('Failed to get L1 blob base fee', attempt);
|
|
128
109
|
}
|
|
129
110
|
|
|
130
|
-
let priorityFee
|
|
131
|
-
// Get competitive priority fee using strategy
|
|
132
|
-
// Reconstruct the results object with the same keys as the promises
|
|
133
|
-
const resultsObject: Record<string, PromiseSettledResult<unknown>> = {};
|
|
134
|
-
strategyPromiseKeys.forEach((key, index) => {
|
|
135
|
-
resultsObject[key] = strategyResults[index];
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
const result = CurrentStrategy.calculate(resultsObject as any, {
|
|
139
|
-
gasConfig,
|
|
140
|
-
isBlobTx,
|
|
141
|
-
logger: this.logger,
|
|
142
|
-
});
|
|
143
|
-
priorityFee = result.priorityFee;
|
|
111
|
+
let priorityFee = strategyPriorityFee;
|
|
144
112
|
|
|
145
113
|
// Apply minimum priority fee floor if configured
|
|
146
114
|
if (gasConfig.minimumPriorityFeePerGas) {
|
|
@@ -156,7 +124,7 @@ export class ReadOnlyL1TxUtils {
|
|
|
156
124
|
}
|
|
157
125
|
let maxFeePerGas = baseFee;
|
|
158
126
|
|
|
159
|
-
let maxFeePerBlobGas = blobBaseFee;
|
|
127
|
+
let maxFeePerBlobGas = blobBaseFee ?? 0n;
|
|
160
128
|
|
|
161
129
|
// Bump base fee so it's valid for next blocks if it stalls
|
|
162
130
|
const numBlocks = Math.ceil(gasConfig.stallTimeMs! / BLOCK_TIME_MS);
|
|
@@ -250,7 +218,7 @@ export class ReadOnlyL1TxUtils {
|
|
|
250
218
|
baseFee: formatGwei(baseFee),
|
|
251
219
|
maxFeePerGas: formatGwei(maxFeePerGas),
|
|
252
220
|
maxPriorityFeePerGas: formatGwei(maxPriorityFeePerGas),
|
|
253
|
-
blobBaseFee: formatGwei(blobBaseFee),
|
|
221
|
+
blobBaseFee: formatGwei(blobBaseFee ?? 0n),
|
|
254
222
|
maxFeePerBlobGas: formatGwei(maxFeePerBlobGas),
|
|
255
223
|
},
|
|
256
224
|
);
|
|
@@ -448,11 +416,4 @@ export class ReadOnlyL1TxUtils {
|
|
|
448
416
|
});
|
|
449
417
|
return bumpedGasLimit;
|
|
450
418
|
}
|
|
451
|
-
|
|
452
|
-
/**
|
|
453
|
-
* Helper function to retry RPC calls twice
|
|
454
|
-
*/
|
|
455
|
-
private tryTwice<T>(fn: () => Promise<T>, description: string): Promise<T> {
|
|
456
|
-
return retry<T>(fn, description, makeBackoff(times(2, () => 0)), this.logger, true);
|
|
457
|
-
}
|
|
458
419
|
}
|
package/src/queries.ts
CHANGED
|
@@ -103,7 +103,7 @@ export async function getL1ContractsConfig(
|
|
|
103
103
|
ejectionThreshold,
|
|
104
104
|
localEjectionThreshold,
|
|
105
105
|
slashingQuorum: Number(slashingQuorum),
|
|
106
|
-
slashingRoundSizeInEpochs: Number(slashingRoundSize / aztecEpochDuration),
|
|
106
|
+
slashingRoundSizeInEpochs: Number(Number(slashingRoundSize) / aztecEpochDuration),
|
|
107
107
|
slashingLifetimeInRounds: Number(slashingLifetimeInRounds),
|
|
108
108
|
slashingExecutionDelayInRounds: Number(slashingExecutionDelayInRounds),
|
|
109
109
|
slashingVetoer,
|
|
@@ -111,7 +111,7 @@ export async function getL1ContractsConfig(
|
|
|
111
111
|
manaTarget,
|
|
112
112
|
provingCostPerMana: provingCostPerMana,
|
|
113
113
|
rollupVersion: Number(rollupVersion),
|
|
114
|
-
genesisArchiveTreeRoot,
|
|
114
|
+
genesisArchiveTreeRoot: genesisArchiveTreeRoot.toString(),
|
|
115
115
|
exitDelaySeconds: Number(exitDelay),
|
|
116
116
|
slasherFlavor: slasherProposer?.type ?? 'tally',
|
|
117
117
|
slashingOffsetInRounds: Number(slashingOffsetInRounds),
|
|
@@ -156,7 +156,7 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
|
|
|
156
156
|
let committee: EthAddress[] | undefined;
|
|
157
157
|
if (l2Epoch !== this.l2EpochNumber) {
|
|
158
158
|
this.l2EpochNumber = l2Epoch;
|
|
159
|
-
committee =
|
|
159
|
+
committee = await this.rollup.getCurrentEpochCommittee();
|
|
160
160
|
this.emit('l2-epoch', { l2EpochNumber: l2Epoch, timestamp, committee });
|
|
161
161
|
msg += ` starting new epoch ${this.l2EpochNumber} `;
|
|
162
162
|
}
|