diff --git a/README.md b/README.md index aa9cdd4..ef10ca6 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,11 @@ This is a library with a collection of onchain and offchain gas price oracle URL Current offchain list: -- https://ethgasstation.info/json/ethgasAPI.json - https://etherchain.org/api/gasnow Current onchain list: -- [chainlink](https://etherscan.io/address/0x169e633a2d1e6c10dd91238ba11c4a708dfef37c#readContract) +- [Chainlink aggregator](https://etherscan.io/address/0x169e633a2d1e6c10dd91238ba11c4a708dfef37c#readContract) ### Binance Smart Chain @@ -25,13 +24,14 @@ Current offchain list: Current offchain list: -- https://blockscout.com/xdai/mainnet/api/v1/gas-price-oracle +- https://gnosis.blockscout.com/api/v1/gas-price-oracle ### Polygon (Matic) Network Current offchain list: -- https://gasstation-mainnet.matic.network/ +- https://gasstation.polygon.technology/v2 +- https://matic-gas-station.tornado.ws ### Avalanche C Network diff --git a/src/config/mainnet.ts b/src/config/mainnet.ts index add5f9d..fdee3b0 100644 --- a/src/config/mainnet.ts +++ b/src/config/mainnet.ts @@ -1,16 +1,5 @@ import { OffChainOracle, OffChainOracles, OnChainOracle, OnChainOracles } from '@/services' -const ethgasstation: OffChainOracle = { - name: 'ethgasstation', - url: 'https://ethgasstation.info/json/ethgasAPI.json', - instantPropertyName: 'fastest', - fastPropertyName: 'fast', - standardPropertyName: 'average', - lowPropertyName: 'safeLow', - denominator: 10, - additionalDataProperty: null, -} - const etherchain: OffChainOracle = { name: 'etherchain', url: 'https://etherchain.org/api/gasnow', @@ -30,7 +19,6 @@ const chainlink: OnChainOracle = { } export const offChainOracles: OffChainOracles = { - ethgasstation, etherchain, } diff --git a/src/config/polygon.ts b/src/config/polygon.ts index 04fe8ce..526cf19 100644 --- a/src/config/polygon.ts +++ b/src/config/polygon.ts @@ -2,10 +2,21 @@ import { OffChainOracle, OffChainOracles, OnChainOracles } from '@/services' const maticGasStation: OffChainOracle = { name: 'maticGasStation', - url: 'https://gasstation-mainnet.matic.network', - instantPropertyName: 'fastest', - fastPropertyName: 'fast', - standardPropertyName: 'standard', + url: 'https://gasstation.polygon.technology/v2', + instantPropertyName: 'fast.maxFee', + fastPropertyName: 'fast.maxFee', + standardPropertyName: 'standard.maxFee', + lowPropertyName: 'safeLow.maxFee', + denominator: 1, + additionalDataProperty: null, +} + +const tornadoMaticGasStation: OffChainOracle = { + name: 'tornadoMGasStation', + url: 'https://matic-gas-station.tornado.ws', + instantPropertyName: 'standard', + fastPropertyName: 'standard', + standardPropertyName: 'safeLow', lowPropertyName: 'safeLow', denominator: 1, additionalDataProperty: null, @@ -13,6 +24,7 @@ const maticGasStation: OffChainOracle = { export const offChainOracles: OffChainOracles = { maticGasStation, + tornadoMaticGasStation, } export const onChainOracles: OnChainOracles = {} diff --git a/src/config/xdai.ts b/src/config/xdai.ts index 9133848..04767bd 100644 --- a/src/config/xdai.ts +++ b/src/config/xdai.ts @@ -2,7 +2,7 @@ import { OffChainOracle, OffChainOracles, OnChainOracles } from '@/services' const blockscout: OffChainOracle = { name: 'blockscout', - url: 'https://blockscout.com/xdai/mainnet/api/v1/gas-price-oracle', + url: 'https://gnosis.blockscout.com/api/v1/gas-price-oracle', instantPropertyName: 'fast', fastPropertyName: 'average', standardPropertyName: 'slow', diff --git a/src/services/legacy-gas-price/legacy.ts b/src/services/legacy-gas-price/legacy.ts index 1f55086..a2961d8 100644 --- a/src/services/legacy-gas-price/legacy.ts +++ b/src/services/legacy-gas-price/legacy.ts @@ -16,6 +16,7 @@ import { import { ChainId, NETWORKS } from '@/config' import { RpcFetcher, NodeJSCache } from '@/services' +import { resolvePropertyPath } from '@/utils' import { GWEI, DEFAULT_TIMEOUT, GWEI_PRECISION, DEFAULT_BLOCK_DURATION } from '@/constants' import { MULTIPLIERS, DEFAULT_GAS_PRICE } from './constants' @@ -297,17 +298,17 @@ export class LegacyGasPriceOracle implements LegacyOracle { const response = await axios.get(url, { timeout: this.configuration.timeout }) if (response.status === 200) { - const gas = additionalDataProperty ? response.data[additionalDataProperty] : response.data + const gas = resolvePropertyPath(response.data, additionalDataProperty) - if (Number(gas[fastPropertyName]) === 0) { + if (Number(resolvePropertyPath(gas, fastPropertyName)) === 0) { throw new Error(`${name} oracle provides corrupted values`) } const gasPrices: GasPrice = { - instant: parseFloat(gas[instantPropertyName]) / denominator, - fast: parseFloat(gas[fastPropertyName]) / denominator, - standard: parseFloat(gas[standardPropertyName]) / denominator, - low: parseFloat(gas[lowPropertyName]) / denominator, + instant: parseFloat(resolvePropertyPath(gas, instantPropertyName)) / denominator, + fast: parseFloat(resolvePropertyPath(gas, fastPropertyName)) / denominator, + standard: parseFloat(resolvePropertyPath(gas, standardPropertyName)) / denominator, + low: parseFloat(resolvePropertyPath(gas, lowPropertyName)) / denominator, } return LegacyGasPriceOracle.normalize(gasPrices) } else { diff --git a/src/utils/index.ts b/src/utils/index.ts index 73e88fb..bf4c53a 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -5,4 +5,43 @@ const sleep = (time: number): Promise => { return new Promise((res) => setTimeout(() => res(true), time)) } -export { sleep } +/** + * Returns the recursively resolved value of the object's subproperty given the properties path, separated by dots. + * If properties path is null, undefined or an empty string - returns the object itself + * @param obj - The object, from which get property or subproperty + * @param propertiesInString - Property name or properties chained string, like 'user.email.domain' + * @returns The value of the subproperty by path or object itself + * + * @example + * + * ### Object + * ```ts + * const x = { + * y: { + * z: 11 + * } + * }; + * ``` + * + * ### Property path in object + * ```ts + * const propertyPath = 'y.z'; + * ``` + * + * ### Usage + * ```ts + * const subpropertyValue = resolvePropertyPath(x, propertyPath); + * ``` + * + * ### Result (subproperty value) + * ```ts + * 11 + * ``` + */ +const resolvePropertyPath = (obj: object, propertyPath: string | undefined | null): any => { + const properties = propertyPath?.split('.') || [] + + return properties.reduce((curr: { [key: string]: any }, nextProperty: string) => curr[nextProperty], obj) +} + +export { sleep, resolvePropertyPath }