56 lines
2.2 KiB
TypeScript
56 lines
2.2 KiB
TypeScript
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';
|
|
|
|
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 blockGasPricesObservable = new Observable<GasPrices>((observer) => {
|
|
provider.on('block', async (blockNumber) => {
|
|
try {
|
|
const block = 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"));
|
|
|
|
// 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`)
|
|
|
|
observer.next({ fast, average, slow } as GasPrices);
|
|
} 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;
|
|
}),
|
|
catchError(err => throwError(() => new Error(err))),
|
|
retry(2)
|
|
);
|
|
|
|
export { averageGasPricesObservable }; |