// https://eips.ethereum.org/EIPS/eip-1559 import { UintSchema } from "@ethernauta/core" import type { Readable, ResolvedReader, } from "@ethernauta/transport" import { bigint_to_hex } from "@ethernauta/utils" import { parse, tupleWithRest } from "valibot" import { eth_feeHistory } from "../method/fee-market" import { type Fees1559, Fees1559Schema } from "./fees" import { type Estimate1559FeesParameters, Estimate1559FeesParametersSchema, } from "./parameters" // Sample window matches viem's default: enough blocks to // smooth single-block volatility, few enough to react quickly. const SAMPLE_BLOCK_COUNT = parse(UintSchema, "0x4") // Fixed-point precision for the base-fee × multiplier step. // 1e6 keeps the multiplier resolution at 6 decimal digits // while staying within safe-integer math. const MULTIPLIER_PRECISION = 1_000_000n const RewardRowSchema = tupleWithRest( [UintSchema], UintSchema, ) const RewardMatrixSchema = tupleWithRest( [RewardRowSchema], RewardRowSchema, ) const BaseFeeListSchema = tupleWithRest( [UintSchema], UintSchema, ) export function estimate_1559_fees( _parameters: Estimate1559FeesParameters, ): Readable { return async ( resolved: ResolvedReader, ): Promise => { const parameters = parse( Estimate1559FeesParametersSchema, _parameters, ) const fee_history = await eth_feeHistory({ blockCount: SAMPLE_BLOCK_COUNT, newestBlock: "latest", rewardPercentiles: [parameters.priority_percentile], })(resolved) const matrix = parse( RewardMatrixSchema, fee_history.reward, ) const samples = matrix.map((row) => BigInt(row[0])) const sum = samples.reduce((a, b) => a + b, 0n) const priority = sum / BigInt(samples.length) // baseFeePerGas is ordered oldest → newest; the last // entry is the next-block predicted fee. Reverse so the // tuple schema can pin its non-emptiness at [0]. const reversed_base_fees = parse( BaseFeeListSchema, [...fee_history.baseFeePerGas].reverse(), ) const base = BigInt(reversed_base_fees[0]) const scaled_multiplier = BigInt( Math.round( parameters.base_fee_multiplier * Number(MULTIPLIER_PRECISION), ), ) const max_fee = (base * scaled_multiplier) / MULTIPLIER_PRECISION + priority return parse(Fees1559Schema, { base_fee_per_gas: bigint_to_hex(base), max_priority_fee_per_gas: bigint_to_hex(priority), max_fee_per_gas: bigint_to_hex(max_fee), }) } }