import 'dotenv/config.js'; import { WebSocketProvider, formatUnits } from 'ethers'; import { Observable, throwError } from 'rxjs'; import { catchError, map, scan, retry } from 'rxjs/operators'; import { GasPrices } from '../types/gasPrices'; const rpcUrl = process.env.RPC_URL || "wss://ropsten.infura.io/ws/v3/YOUR_INFURA_PROJECT_ID"; const provider = new WebSocketProvider(rpcUrl); const blockBaseFeePerGasObservable$ = new Observable((observer) => { provider.on('block', async (blockNumber) => { try { const { baseFeePerGas } = await provider.getBlock(blockNumber, true) || {}; if (!baseFeePerGas) throw new Error(`Error fetching block! ${blockNumber}`); // Log averages every 10 blocks if (blockNumber % 10 == 0) console.log( `Found new block data for ${blockNumber}! Gas price: 🐢 ${Number(formatUnits(baseFeePerGas, "gwei")).toFixed(2)} Gwei` ) observer.next(Number(formatUnits(baseFeePerGas, "gwei"))); } catch (error) { observer.error(`Error fetching block! ${error}`); } }); }); const baseGasPricesObservable$ = blockBaseFeePerGasObservable$.pipe( scan( (acc: GasPrices, curr: number): GasPrices => { // Keep only the 20 latest values const values: number[] = acc.values ? [...acc.values.slice(-19), curr] : [curr]; const fast: number = Math.max(...values); const slow: number = Math.min(...values); const sum: number = values.reduce((a, b) => a + b, 0); const average: number = sum / values.length; return { values, fast, slow, average }; }, { values: [], fast: -Infinity, slow: Infinity, average: NaN } // Initial value ), // Only emit the computed prices map((computedGasPrices: GasPrices): GasPrices => { const { fast, average, slow } = computedGasPrices; return { fast: Math.round(fast), average: Math.round(average), slow: Math.round(slow) }; }), catchError(err => throwError(() => new Error(err))), retry(2) ); export { baseGasPricesObservable$ };