Refactor to compute GasPrices differently

This commit is contained in:
MrTuxedo 2023-04-22 15:57:20 -07:00
parent ef228254b3
commit f78674578b
3 changed files with 35 additions and 31 deletions

View File

@ -1,6 +1,5 @@
import 'dotenv/config.js'; import 'dotenv/config.js';
import { WebSocketProvider, formatUnits } from 'ethers'; import { WebSocketProvider, formatUnits } from 'ethers';
import { sortBy } from 'lodash';
import { Observable, throwError } from 'rxjs'; import { Observable, throwError } from 'rxjs';
import { catchError, map, scan, retry } from 'rxjs/operators'; 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 provider = new WebSocketProvider(rpcUrl);
const blockGasPricesObservable = new Observable<GasPrices>((observer) => { const blockBaseFeePerGasObservable$ = new Observable<number>((observer) => {
provider.on('block', async (blockNumber) => { provider.on('block', async (blockNumber) => {
try { try {
const block = await provider.getBlock(blockNumber, true); const { baseFeePerGas } = await provider.getBlock(blockNumber, true) || {};
if (!block) throw new Error(`Error fetching block! ${blockNumber}`); if (!baseFeePerGas) 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"));
// Log averages every 10 blocks // Log averages every 10 blocks
if (blockNumber % 10 == 0) console.log(`Found new block data for ${blockNumber}! if (blockNumber % 10 == 0) console.log(
Gas price spreads: ${fast.toFixed(2)} 🚶 ${average.toFixed(2)} 🐢 ${slow.toFixed(2)} Gwei`) `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) { } catch (error) {
observer.error(`Error fetching block! ${error}`); observer.error(`Error fetching block! ${error}`);
} }
}); });
}); });
const averageGasPricesObservable = blockGasPricesObservable.pipe( const baseGasPricesObservable$ = blockBaseFeePerGasObservable$.pipe(
scan((acc, curr) => [...acc.slice(-19), curr], [] as GasPrices[]), scan<number, GasPrices>(
map((blocks) => { (acc: GasPrices, curr: number): GasPrices => {
const { fast, average, slow } = blocks // Keep only the 20 latest values
.reduce((sum, block) => const values: number[] = acc.values ? [...acc.values.slice(-19), curr] : [curr];
({ // Find sums
fast: sum.fast + block.fast, const fast: number = Math.max(...values);
average: sum.average + block.average, const slow: number = Math.min(...values);
slow: sum.slow + block.slow const sum: number = values.reduce((a, b) => a + b, 0);
}), { fast: 0, average: 0, slow: 0 } as GasPrices); const average: number = sum / values.length;
return { // Then average them
fast: Math.round(fast / blocks.length), return { values, fast, slow, average };
average: Math.round(average / blocks.length), },
slow: Math.round(slow / blocks.length), { values: [], fast: -Infinity, slow: Infinity, average: NaN } // Initial value
} as GasPrices; ),
// Only emit the computed prices
map<GasPrices, GasPrices>((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))), catchError(err => throwError(() => new Error(err))),
retry(2) retry(2)
); );
export { averageGasPricesObservable }; export { baseGasPricesObservable$ };

View File

@ -9,7 +9,7 @@ import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import { ActivityType, GatewayIntentBits } from 'discord.js'; import { ActivityType, GatewayIntentBits } from 'discord.js';
import { averageGasPricesObservable } from './blockchain'; import { baseGasPricesObservable$ } from './blockchain';
import { deployCommands } from './deploy'; import { deployCommands } from './deploy';
import { DiscordClient } from './discordClient'; import { DiscordClient } from './discordClient';
import { createGasAlertChecker } from './gasAlertChecker'; import { createGasAlertChecker } from './gasAlertChecker';
@ -76,7 +76,7 @@ client.login(token)
}) })
.then(() => { .then(() => {
// Start listening to blockchain // Start listening to blockchain
averageGasPricesObservable.subscribe({ baseGasPricesObservable$.subscribe({
next: async (averageGasPrices) => { next: async (averageGasPrices) => {
setDiscordStatus(averageGasPrices); setDiscordStatus(averageGasPrices);
await redisClient.set('current-prices', JSON.stringify(averageGasPrices)) await redisClient.set('current-prices', JSON.stringify(averageGasPrices))

View File

@ -2,4 +2,5 @@ export interface GasPrices {
fast: number; fast: number;
average: number; average: number;
slow: number; slow: number;
} values?: number[];
}