@aztec/ethereum 0.0.1-commit.c7c42ec → 0.0.1-commit.d1f2d6c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/config.d.ts +15 -28
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +46 -55
- 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.d.ts +3 -1
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +9 -1
- package/dest/contracts/governance_proposer.js +382 -8
- package/dest/contracts/inbox.d.ts +18 -1
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +32 -1
- package/dest/contracts/index.d.ts +3 -1
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +2 -0
- package/dest/contracts/log.d.ts +13 -0
- package/dest/contracts/log.d.ts.map +1 -0
- package/dest/contracts/log.js +1 -0
- package/dest/contracts/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 +160 -96
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +668 -129
- package/dest/deploy_aztec_l1_contracts.d.ts +15 -2
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +74 -12
- package/dest/generated/l1-contracts-defaults.d.ts +30 -0
- package/dest/generated/l1-contracts-defaults.d.ts.map +1 -0
- package/dest/generated/l1-contracts-defaults.js +30 -0
- package/dest/l1_artifacts.d.ts +4866 -1513
- 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.d.ts +2 -2
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +6 -3
- package/dest/test/chain_monitor.js +1 -2
- package/dest/test/eth_cheat_codes.d.ts +13 -1
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.d.ts +3 -2
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +10 -2
- package/package.json +8 -7
- package/src/config.ts +55 -54
- package/src/contracts/README.md +157 -0
- package/src/contracts/fee_asset_handler.ts +8 -7
- package/src/contracts/governance.ts +8 -1
- package/src/contracts/inbox.ts +48 -1
- package/src/contracts/index.ts +2 -0
- package/src/contracts/log.ts +13 -0
- package/src/contracts/outbox.ts +98 -0
- package/src/contracts/rollup.ts +333 -93
- package/src/deploy_aztec_l1_contracts.ts +76 -14
- package/src/generated/l1-contracts-defaults.ts +32 -0
- 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 +5 -3
- package/src/test/chain_monitor.ts +1 -1
- package/src/test/rollup_cheat_codes.ts +12 -3
|
@@ -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, readFileSync, rmSync, writeFileSync } 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,77 @@ 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
|
+
logger.verbose(`Using cached deployment directory: ${preparedDeployDir}`);
|
|
145
|
+
return preparedDeployDir;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const basePath = getL1ContractsPath();
|
|
149
|
+
logger.verbose(`Preparing L1 contracts from: ${basePath}`);
|
|
150
|
+
const tempDir = mkdtempSync(join(tmpdir(), '.foundry-deploy-'));
|
|
151
|
+
logger.verbose(`Created temp directory for deployment: ${tempDir}`);
|
|
152
|
+
preparedDeployDir = tempDir;
|
|
153
|
+
process.on('exit', cleanupDeployDir);
|
|
154
|
+
|
|
155
|
+
// Copy all dirs with preserved timestamps (required for forge cache validity)
|
|
156
|
+
const copyOpts = { recursive: true, preserveTimestamps: true };
|
|
157
|
+
cpSync(join(basePath, 'out'), join(tempDir, 'out'), copyOpts);
|
|
158
|
+
cpSync(join(basePath, 'lib'), join(tempDir, 'lib'), copyOpts);
|
|
159
|
+
cpSync(join(basePath, 'cache'), join(tempDir, 'cache'), copyOpts);
|
|
160
|
+
cpSync(join(basePath, 'src'), join(tempDir, 'src'), copyOpts);
|
|
161
|
+
cpSync(join(basePath, 'script'), join(tempDir, 'script'), copyOpts);
|
|
162
|
+
cpSync(join(basePath, 'generated'), join(tempDir, 'generated'), copyOpts);
|
|
163
|
+
// Kludge: copy test/ to appease forge cache which references test/shouting.t.sol
|
|
164
|
+
cpSync(join(basePath, 'test'), join(tempDir, 'test'), copyOpts);
|
|
165
|
+
cpSync(join(basePath, 'foundry.lock'), join(tempDir, 'foundry.lock'));
|
|
166
|
+
|
|
167
|
+
// Update foundry.toml to use absolute path to solc binary (avoids copying to noexec tmpfs)
|
|
168
|
+
const foundryTomlPath = join(basePath, 'foundry.toml');
|
|
169
|
+
let foundryToml = readFileSync(foundryTomlPath, 'utf-8');
|
|
170
|
+
const solcPathMatch = foundryToml.match(/solc\s*=\s*"\.\/solc-([^"]+)"/);
|
|
171
|
+
if (solcPathMatch) {
|
|
172
|
+
const solcVersion = solcPathMatch[1];
|
|
173
|
+
const absoluteSolcPath = join(basePath, `solc-${solcVersion}`);
|
|
174
|
+
foundryToml = foundryToml.replace(/solc\s*=\s*"\.\/solc-[^"]+"/, `solc = "${absoluteSolcPath}"`);
|
|
175
|
+
logger.verbose(`Updated solc path in foundry.toml to: ${absoluteSolcPath}`);
|
|
176
|
+
}
|
|
177
|
+
writeFileSync(join(tempDir, 'foundry.toml'), foundryToml);
|
|
178
|
+
|
|
179
|
+
mkdirSync(join(tempDir, 'broadcast'));
|
|
180
|
+
return tempDir;
|
|
181
|
+
}
|
|
182
|
+
|
|
121
183
|
/**
|
|
122
184
|
* Computes the validator data for passing to Solidity.
|
|
123
185
|
* Only computes the G2 public key (which requires scalar multiplication on G2, not available in EVM).
|
|
@@ -211,7 +273,6 @@ export async function deployAztecL1Contracts(
|
|
|
211
273
|
'Initial validator funding requires minting tokens, which is not possible with an external token.',
|
|
212
274
|
);
|
|
213
275
|
}
|
|
214
|
-
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
215
276
|
const chain = createEthereumChain([rpcUrl], chainId);
|
|
216
277
|
|
|
217
278
|
const l1Client = createExtendedL1Client([rpcUrl], privateKey, chain.chainInfo);
|
|
@@ -240,8 +301,8 @@ export async function deployAztecL1Contracts(
|
|
|
240
301
|
}
|
|
241
302
|
}
|
|
242
303
|
|
|
243
|
-
//
|
|
244
|
-
const l1ContractsPath =
|
|
304
|
+
// Use foundry-artifacts from l1-artifacts package
|
|
305
|
+
const l1ContractsPath = prepareL1ContractsForDeployment();
|
|
245
306
|
|
|
246
307
|
const FORGE_SCRIPT = 'script/deploy/DeployAztecL1Contracts.s.sol';
|
|
247
308
|
await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
@@ -258,7 +319,7 @@ export async function deployAztecL1Contracts(
|
|
|
258
319
|
}
|
|
259
320
|
|
|
260
321
|
// From heuristic testing. More caused issues with anvil.
|
|
261
|
-
const MAGIC_ANVIL_BATCH_SIZE =
|
|
322
|
+
const MAGIC_ANVIL_BATCH_SIZE = 8;
|
|
262
323
|
// Anvil seems to stall with unbounded batch size. Otherwise no max batch size is desirable.
|
|
263
324
|
const forgeArgs = [
|
|
264
325
|
'script',
|
|
@@ -447,6 +508,7 @@ export function getDeployAztecL1ContractsEnvVars(args: DeployAztecL1ContractsArg
|
|
|
447
508
|
AZTEC_EJECTION_THRESHOLD: args.ejectionThreshold?.toString(),
|
|
448
509
|
AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE: args.governanceProposerRoundSize?.toString(),
|
|
449
510
|
AZTEC_GOVERNANCE_PROPOSER_QUORUM: args.governanceProposerQuorum?.toString(),
|
|
511
|
+
AZTEC_GOVERNANCE_VOTING_DURATION: args.governanceVotingDuration?.toString(),
|
|
450
512
|
ZKPASSPORT_DOMAIN: args.zkPassportArgs?.zkPassportDomain,
|
|
451
513
|
ZKPASSPORT_SCOPE: args.zkPassportArgs?.zkPassportScope,
|
|
452
514
|
} as const;
|
|
@@ -481,11 +543,13 @@ export function getDeployRollupForUpgradeEnvVars(
|
|
|
481
543
|
AZTEC_PROOF_SUBMISSION_EPOCHS: args.aztecProofSubmissionEpochs.toString(),
|
|
482
544
|
AZTEC_LOCAL_EJECTION_THRESHOLD: args.localEjectionThreshold.toString(),
|
|
483
545
|
AZTEC_SLASHING_LIFETIME_IN_ROUNDS: args.slashingLifetimeInRounds.toString(),
|
|
546
|
+
AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS: args.slashingExecutionDelayInRounds.toString(),
|
|
484
547
|
AZTEC_SLASHING_VETOER: args.slashingVetoer.toString(),
|
|
485
548
|
AZTEC_SLASHING_DISABLE_DURATION: args.slashingDisableDuration.toString(),
|
|
486
549
|
AZTEC_MANA_TARGET: args.manaTarget.toString(),
|
|
487
550
|
AZTEC_EXIT_DELAY_SECONDS: args.exitDelaySeconds.toString(),
|
|
488
551
|
AZTEC_PROVING_COST_PER_MANA: args.provingCostPerMana.toString(),
|
|
552
|
+
AZTEC_INITIAL_ETH_PER_FEE_ASSET: args.initialEthPerFeeAsset.toString(),
|
|
489
553
|
AZTEC_SLASHER_FLAVOR: args.slasherFlavor,
|
|
490
554
|
AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS: args.slashingRoundSizeInEpochs.toString(),
|
|
491
555
|
AZTEC_SLASHING_QUORUM: args.slashingQuorum?.toString(),
|
|
@@ -513,10 +577,8 @@ export const deployRollupForUpgrade = async (
|
|
|
513
577
|
| 'zkPassportArgs'
|
|
514
578
|
>,
|
|
515
579
|
) => {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
// Relative location of l1-contracts in monorepo or docker image.
|
|
519
|
-
const l1ContractsPath = resolve(currentDir, '..', '..', '..', 'l1-contracts');
|
|
580
|
+
// Use foundry-artifacts from l1-artifacts package
|
|
581
|
+
const l1ContractsPath = prepareL1ContractsForDeployment();
|
|
520
582
|
|
|
521
583
|
const FORGE_SCRIPT = 'script/deploy/DeployRollupForUpgrade.s.sol';
|
|
522
584
|
await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Auto-generated from spartan/environments/network-defaults.yml
|
|
2
|
+
// Do not edit manually - run yarn generate to regenerate
|
|
3
|
+
|
|
4
|
+
/** Default L1 contracts configuration values from network-defaults.yml */
|
|
5
|
+
export const l1ContractsDefaultEnv = {
|
|
6
|
+
ETHEREUM_SLOT_DURATION: 12,
|
|
7
|
+
AZTEC_SLOT_DURATION: 36,
|
|
8
|
+
AZTEC_EPOCH_DURATION: 32,
|
|
9
|
+
AZTEC_TARGET_COMMITTEE_SIZE: 48,
|
|
10
|
+
AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET: 2,
|
|
11
|
+
AZTEC_LAG_IN_EPOCHS_FOR_RANDAO: 2,
|
|
12
|
+
AZTEC_ACTIVATION_THRESHOLD: 100000000000000000000,
|
|
13
|
+
AZTEC_EJECTION_THRESHOLD: 50000000000000000000,
|
|
14
|
+
AZTEC_LOCAL_EJECTION_THRESHOLD: 98000000000000000000,
|
|
15
|
+
AZTEC_EXIT_DELAY_SECONDS: 172800,
|
|
16
|
+
AZTEC_INBOX_LAG: 1,
|
|
17
|
+
AZTEC_PROOF_SUBMISSION_EPOCHS: 1,
|
|
18
|
+
AZTEC_MANA_TARGET: 100000000,
|
|
19
|
+
AZTEC_PROVING_COST_PER_MANA: 100,
|
|
20
|
+
AZTEC_INITIAL_ETH_PER_FEE_ASSET: 10000000,
|
|
21
|
+
AZTEC_SLASHER_FLAVOR: 'tally',
|
|
22
|
+
AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS: 4,
|
|
23
|
+
AZTEC_SLASHING_LIFETIME_IN_ROUNDS: 5,
|
|
24
|
+
AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS: 0,
|
|
25
|
+
AZTEC_SLASHING_OFFSET_IN_ROUNDS: 2,
|
|
26
|
+
AZTEC_SLASHING_VETOER: '0x0000000000000000000000000000000000000000',
|
|
27
|
+
AZTEC_SLASHING_DISABLE_DURATION: 432000,
|
|
28
|
+
AZTEC_SLASH_AMOUNT_SMALL: 10000000000000000000,
|
|
29
|
+
AZTEC_SLASH_AMOUNT_MEDIUM: 20000000000000000000,
|
|
30
|
+
AZTEC_SLASH_AMOUNT_LARGE: 50000000000000000000,
|
|
31
|
+
AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE: 300,
|
|
32
|
+
} as const;
|
|
@@ -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,
|