From ce5944258c494bbfa6bb51ea1bddf8774f79d02f Mon Sep 17 00:00:00 2001 From: MrTuxedo Date: Sat, 22 Apr 2023 15:57:20 -0700 Subject: [PATCH] Refactor to compute GasPrices differently --- src/blockchain.ts | 59 +++++++++++++++++++++++--------------------- src/index.ts | 4 +-- types/gasPrices.d.ts | 3 ++- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/src/blockchain.ts b/src/blockchain.ts index 0b471c4..6fffca6 100644 --- a/src/blockchain.ts +++ b/src/blockchain.ts @@ -1,6 +1,5 @@ import 'dotenv/config.js'; import { WebSocketProvider, formatUnits } from 'ethers'; -import { sortBy } from 'lodash'; import { Observable, throwError } from 'rxjs'; import { catchError, map, scan, retry } from 'rxjs/operators'; @@ -10,47 +9,51 @@ const rpcUrl = process.env.RPC_URL || "wss://ropsten.infura.io/ws/v3/YOUR_INFURA const provider = new WebSocketProvider(rpcUrl); -const blockGasPricesObservable = new Observable((observer) => { +const blockBaseFeePerGasObservable$ = new Observable((observer) => { provider.on('block', async (blockNumber) => { try { - const block = await provider.getBlock(blockNumber, true); + const { baseFeePerGas } = await provider.getBlock(blockNumber, true) || {}; - if (!block) throw new Error(`Error fetching block! ${blockNumber}`); - - const gasPrices = sortBy(block.prefetchedTransactions, ['gasPrice']).map(x => x.gasPrice); - const fast = Number(formatUnits(gasPrices[Math.floor(gasPrices.length * 0.9)], "gwei")); - const average = Number(formatUnits(gasPrices[Math.floor(gasPrices.length / 2)], "gwei")); - const slow = Number(formatUnits(gasPrices[Math.floor(gasPrices.length * 0.05)], "gwei")); + 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 spreads: ⚡ ${fast.toFixed(2)} ⦚⦚ 🚶 ${average.toFixed(2)} ⦚⦚ 🐢 ${slow.toFixed(2)} Gwei`) + if (blockNumber % 1 == 0) console.log( + `Found new block data for ${blockNumber}! Gas price: 🐢 ${Number(formatUnits(baseFeePerGas, "gwei")).toFixed(2)} Gwei` + ) - observer.next({ fast, average, slow } as GasPrices); + observer.next(Number(formatUnits(baseFeePerGas, "gwei"))); } catch (error) { observer.error(`Error fetching block! ${error}`); } }); }); -const averageGasPricesObservable = blockGasPricesObservable.pipe( - scan((acc, curr) => [...acc.slice(-19), curr], [] as GasPrices[]), - map((blocks) => { - const { fast, average, slow } = blocks - .reduce((sum, block) => - ({ // Find sums - fast: sum.fast + block.fast, - average: sum.average + block.average, - slow: sum.slow + block.slow - }), { fast: 0, average: 0, slow: 0 } as GasPrices); - return { // Then average them - fast: Math.round(fast / blocks.length), - average: Math.round(average / blocks.length), - slow: Math.round(slow / blocks.length), - } as GasPrices; +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 { averageGasPricesObservable }; \ No newline at end of file +export { baseGasPricesObservable$ }; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index ddaa369..3156f3b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { ActivityType, GatewayIntentBits } from 'discord.js'; -import { averageGasPricesObservable } from './blockchain'; +import { baseGasPricesObservable$ } from './blockchain'; import { deployCommands } from './deploy'; import { DiscordClient } from './discordClient'; import { createGasAlertChecker } from './gasAlertChecker'; @@ -76,7 +76,7 @@ client.login(token) }) .then(() => { // Start listening to blockchain - averageGasPricesObservable.subscribe({ + baseGasPricesObservable$.subscribe({ next: async (averageGasPrices) => { setDiscordStatus(averageGasPrices); await redisClient.set('current-prices', JSON.stringify(averageGasPrices)) diff --git a/types/gasPrices.d.ts b/types/gasPrices.d.ts index cd78d49..a1b41e2 100644 --- a/types/gasPrices.d.ts +++ b/types/gasPrices.d.ts @@ -2,4 +2,5 @@ export interface GasPrices { fast: number; average: number; slow: number; -} \ No newline at end of file + values?: number[]; +}