# Gas Price Oracle library for Ethereum dApps [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/peppersec/gas-price-oracle/Node.js%20CI)](https://github.com/peppersec/gas-price-oracle/actions) [![npm](https://img.shields.io/npm/v/gas-price-oracle)](https://www.npmjs.com/package/gas-price-oracle) This is a library with a collection of onchain and offchain gas price oracle URLs ## Supported networks ### Ethereum Mainnet Current offchain list: - https://etherchain.org/api/gasnow Current onchain list: - [Chainlink aggregator](https://etherscan.io/address/0x169e633a2d1e6c10dd91238ba11c4a708dfef37c#readContract) ### Binance Smart Chain Current offchain list: - https://ztake.org/ ### Gnosis Chain Current offchain list: - https://gnosis.blockscout.com/api/v1/gas-price-oracle ### Polygon (Matic) Network Current offchain list: - https://gasstation.polygon.technology/v2 - https://matic-gas-station.tornado.ws ### Avalanche C Network Current offchain list: - https://gavax.blockscan.com/gasapi.ashx?apikey=key&method=gasoracle ## Installation `npm i gas-price-oracle` or `yarn add gas-price-oracle` ## Import ```js const { GasPriceOracle } = require('gas-price-oracle') or import { GasPriceOracle } from 'gas-price-oracle' ``` ## Usage ### Configuration ```typescript type GasPrice = Record<'instant' | 'fast' | 'standard' | 'low', number> type EstimatedGasPrice = { maxFeePerGas: number baseFee: number | undefined maxPriorityFeePerGas: number } type FallbackGasPrices = { gasPrices?: GasPrice estimated?: EstimatedGasPrice } type GasOracleOptions = { chainId?: number timeout?: number defaultRpc?: string blocksCount?: number percentile?: number blockTime?: number // seconds shouldCache?: boolean fallbackGasPrices?: FallbackGasPrices } const options: GasOracleOptions = { chainId: 1, percentile: 5, // Which percentile of effective priority fees to include blocksCount: 10, // How many blocks to consider for priority fee estimation defaultRpc: 'https://api.mycryptoapi.com/eth', blockTime: 10, // seconds shouldCache: false, timeout: 10000, // specifies the number of milliseconds before the request times out. minPriority: 0, // specifies the min maxPriorityFeePerGas. fallbackGasPrices: { gasPrices: { instant: 28, fast: 22, standard: 17, low: 11, }, estimated: { maxFeePerGas: 20, maxPriorityFeePerGas: 3, }, }, } ``` ### The Oracle can cache rpc calls For caching needs to provide to GasOracleOptions `shouldCache: true` `blockTime: ` ### EIP-1559 (estimated) gasPrice only ```typescript const oracle = new GasPriceOracle({ chainId: 1 }) type EstimatedGasPrice = { maxFeePerGas: number baseFee: number | undefined maxPriorityFeePerGas: number } fallbackGasPrices: EstimatedGasPrice = { maxFeePerGas: 20, maxPriorityFeePerGas: 3, } oracle.eip1559.estimateFees(fallbackGasPrices).then((gasPrices: EstimatedGasPrice) => { console.log(gasPrices) // { baseFee: 14, maxFeePerGas: 17, maxPriorityFeePerGas: 3 } }) ``` ### Legacy gasPrice only ```typescript const oracle = new GasPriceOracle({ chainId: 1 }) type GasPrice = Record<'instant' | 'fast' | 'standard' | 'low', number> fallbackGasPrices: GasPrice = { instant: 28, fast: 22, standard: 17, low: 11, } oracle.legacy.gasPrices(fallbackGasPrices).then((gasPrices: GasPrice) => { console.log(gasPrices) // { instant: 21.5, fast: 19, standard: 17, low: 15 } }) ``` The `oracle.legacy.gasPrices` method also accepts `shouldGetMedian` argument (`true`) by default. For more details see [below](#offchain-oracles-only-get-median-price). Under the hood it's a combination of `fetchMedianGasPriceOffChain`(`fetchGasPricesOffChain`) and `fetchGasPricesOnChain` methods. ### Estimated gasPrices (EIP-1559) and Legacy gasPrice ```ts const oracle = new GasPriceOracle(options) type GasPriceWithEstimate = { gasPrices: GasPrice estimate: EstimatedGasPrice } type GasPricesWithEstimateInput = { shouldGetMedian?: boolean fallbackGasPrices?: FallbackGasPrices } // optional fallbackGasPrices const fallbackGasPrices: FallbackGasPrices = { gasPrices: { instant: 28, fast: 22, standard: 17, low: 11, }, estimated: { maxFeePerGas: 20, maxPriorityFeePerGas: 3, }, } oracle.gasPricesWithEstimate({ fallbackGasPrices, shouldGetMedian: true }).then((gasPrices: GasPriceWithEstimate) => { console.log(gasPrices) // { // estimated: { baseFee: 14, maxFeePerGas: 17, maxPriorityFeePerGas: 3 }, // gasPrices: { instant: 21.5, fast: 19, standard: 17, low: 15 } // }} }) ``` ### Estimated gasPrices (EIP-1559) or Legacy gasPrice ```typescript const oracle = new GasPriceOracle(options) type GetGasPriceInput = { isLegacy?: boolean shouldGetMedian?: boolean fallbackGasPrices?: GasPrice } // optional fallbackGasPrices const fallbackGasPrices: FallbackGasPrices = { gasPrices: { instant: 28, fast: 22, standard: 17, low: 11, }, estimated: { maxFeePerGas: 20, maxPriorityFeePerGas: 3, }, } oracle.gasPrices({ fallbackGasPrices, shouldGetMedian: true }).then((gasPrices: GasPrice | EstimatedGasPrice) => { console.log(gasPrices) // { // baseFee: 14, maxFeePerGas: 17, maxPriorityFeePerGas: 3 || // instant: 21.5, fast: 19, standard: 17, low: 15 // }} }) ``` The `gasPrices` method also accepts `isLegacy` argument (`false`) by default. If `isLegacy: true` - `legacy gasPrice` will be provided. If the `estimate Gas` crashes, `legacy gas Price` will be provided. ### Get transaction gasPrice params ```typescript const oracle = new GasPriceOracle(options) type GetTxGasParamsInput = { bumpPercent?: number legacySpeed?: GasPriceKey isLegacy?: boolean shouldGetMedian?: boolean fallbackGasPrices?: FallbackGasPrices } type GetTxGasParamsRes = | { gasPrice: number } | { maxFeePerGas: number maxPriorityFeePerGas: number } const gasParams: GetTxGasParamsRes = await oracle.getTxGasParams({ legacySpeed: 'fast', bumpPercent: 30 }) console.log(gasParams) // { maxFeePerGas: '3f5476a00', maxPriorityFeePerGas: 'b2d05e00' } || { gasPrice: '46c7cfe00' } // equal to: { maxFeePerGas: 17 gwei, maxPriorityFeePerGas: 3 gwei } || { gasPrice: 19 gwei } web3.eth.sendTransaction({ from: '0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8', to: '0xac03bb73b6a9e108530aff4df5077c2b3d481e5a', nonce: '0', gasLimit: '21000', value: '10000000000', ...gasParams, }) ``` `bumpPercent` argument (`0` by default) - response data will increase by `bumpPercent`%. `legacySpeed` argument (`fast` by default) - select the speed of legacy gasPrice. Returns gas info in `wei`, hex-format. ### Offchain oracles only ```typescript const oracle = new GasPriceOracle({ chainId: 1 }) // shouldGetMedian: boolean | undefined oracle.legacy.fetchGasPricesOffChain((shouldGetMedian = true)).then((gasPrices: GasPrice) => { console.log(gasPrices) // { instant: 50, fast: 21, standard: 10, low: 3 } }) ``` ### Offchain oracles only (get median price) ```typescript const oracle = new GasPriceOracle({ chainId: 1 }) oracle.legacy.fetchMedianGasPriceOffChain().then((gasPrices: GasPrice) => { console.log(gasPrices) // { instant: 50, fast: 21, standard: 10, low: 3 } }) ``` This command provides the median gas price of all configured oracles. ### Custom RPC URL for onchain oracles ```typescript const defaultRpc = 'https://mainnet.infura.io/v3/' const oracle = new GasPriceOracle({ defaultRpc, chainId: 1 }) oracle.legacy.fetchGasPricesOnChain().then((gasPrices: number) => { console.log(gasPrices) // 21 }) ``` To get gasPrices from a chain outside of the application's chain list (Binance, Gnosis, Polygon, Avalanche), you should enter the rpcUrl into initial GasPriceOracle options\_ ```typescript const defaultRpc = 'https://rpc.goerli.mudit.blog/' // goerli public rpcUrl const oracle = new GasPriceOracle({ defaultRpc, chainId: 5 }) oracle.gasPrices() ```