From b13a4252ab80256f2d24f7f7140599caa8155304 Mon Sep 17 00:00:00 2001 From: Danil Kovtonyuk Date: Mon, 4 Oct 2021 17:50:53 +1000 Subject: [PATCH] feat: add fetch gas price from rpc --- package.json | 2 +- src/index.ts | 43 ++++++++++++++++++++++++++++++++++++++++++- tests/index.test.ts | 31 +++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9308804..6e3f35f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gas-price-oracle", - "version": "0.3.5", + "version": "0.4.0", "description": "Gas Price Oracle library for Ethereum dApps.", "main": "lib/index.js", "homepage": "https://github.com/peppersec/gas-price-oracle", diff --git a/src/index.ts b/src/index.ts index 5f16d70..82e41ae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -185,6 +185,34 @@ export class GasPriceOracle { throw new Error('All oracles are down. Probably a network error.'); } + async fetchGasPriceFromRpc(): Promise { + const rpcUrl = this.configuration.defaultRpc; + const body = { + jsonrpc: '2.0', + id: 1337, + method: 'eth_gasPrice', + params: [], + }; + try { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const response = await axios.post(rpcUrl!, body, { timeout: this.configuration.timeout }); + if (response.status === 200) { + const { result } = response.data; + let fastGasPrice = new BigNumber(result); + if (fastGasPrice.isZero()) { + throw new Error(`Default RPC provides corrupted values`); + } + fastGasPrice = fastGasPrice.div(1e9); + return fastGasPrice.toNumber(); + } + + throw new Error(`Fetch gasPrice from default RPC failed..`); + } catch (e) { + console.error(e.message); + throw new Error('Default RPC is down. Probably a network error.'); + } + } + async gasPrices(fallbackGasPrices?: GasPrice, median = true): Promise { this.lastGasPrice = this.lastGasPrice || fallbackGasPrices || this.configuration.defaultFallbackGasPrices; try { @@ -206,7 +234,20 @@ export class GasPriceOracle { }; return this.lastGasPrice; } catch (e) { - console.log('Failed to fetch gas prices from onchain oracles. Last known gas will be returned'); + console.log('Failed to fetch gas prices from onchain oracles. Trying from default RPC...'); + } + + try { + const fastGas = await this.fetchGasPriceFromRpc(); + this.lastGasPrice = { + instant: fastGas * 1.3, + fast: fastGas, + standard: fastGas * 0.85, + low: fastGas * 0.5, + }; + return this.lastGasPrice; + } catch (e) { + console.log('Failed to fetch gas prices from default RPC. Last known gas will be returned'); } return this.lastGasPrice; } diff --git a/tests/index.test.ts b/tests/index.test.ts index 567217a..e67d8df 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -119,6 +119,37 @@ describe('fetchGasPricesOnChain', function () { }); }); +describe('fetchGasPriceFromRpc', function () { + it('should work', async function () { + const gas: number = await oracle.fetchGasPriceFromRpc(); + gas.should.be.a('number'); + gas.should.be.above(1); + gas.should.not.be.equal(0); + }); + + it('should work with custom rpc', async function () { + const rpc = 'https://ethereum-rpc.trustwalletapp.com'; + const oracle = new GasPriceOracle({ defaultRpc: rpc }); + oracle.configuration.defaultRpc.should.be.equal(rpc); + const gas: number = await oracle.fetchGasPriceFromRpc(); + + gas.should.be.a('number'); + + gas.should.be.above(1); + gas.should.not.be.equal(0); + }); + + it('should throw if default rpc is down', async function () { + mockery.enable({ useCleanCache: true, warnOnUnregistered: false }); + const { GasPriceOracle } = require('../src/index'); + oracle = new GasPriceOracle(); + await oracle + .fetchGasPriceFromRpc() + .should.be.rejectedWith('Default RPC is down. Probably a network error.'); + mockery.disable(); + }); +}); + describe('gasPrice', function () { it('should work', async function () { const gas: GasPrice = await oracle.gasPrices();