diff --git a/src/PriceBox.tsx b/src/PriceBox.tsx index 60b0903..30ec31e 100644 --- a/src/PriceBox.tsx +++ b/src/PriceBox.tsx @@ -1,17 +1,16 @@ -import React, { useState, useEffect, useMemo, useContext } from "react"; -import { Contract } from "@ethersproject/contracts"; +import React, { useMemo, useContext } from "react"; import { commify, formatUnits } from "@ethersproject/units"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faGasPump } from "@fortawesome/free-solid-svg-icons/faGasPump"; -import AggregatorV3Interface from "@chainlink/contracts/abi/v0.8/AggregatorV3Interface.json"; import { RuntimeContext } from "./useRuntime"; import { formatValue } from "./components/formatter"; import { useLatestBlockHeader } from "./useLatestBlock"; import { useChainInfo } from "./useChainInfo"; +import { useETHUSDRawOracle, useFastGasRawOracle } from "./usePriceOracle"; +// TODO: encapsulate this magic number const ETH_FEED_DECIMALS = 8; -// TODO: reduce duplication with useETHUSDOracle const PriceBox: React.FC = () => { const { provider } = useContext(RuntimeContext); const { @@ -22,37 +21,8 @@ const PriceBox: React.FC = () => { const maybeOutdated: boolean = latestBlock !== undefined && Date.now() / 1000 - latestBlock.timestamp > 3600; - const ethFeed = useMemo( - () => - provider && - new Contract("eth-usd.data.eth", AggregatorV3Interface, provider), - [provider] - ); - const gasFeed = useMemo( - () => - provider && - new Contract("fast-gas-gwei.data.eth", AggregatorV3Interface, provider), - [provider] - ); - - const [latestPriceData, setLatestPriceData] = useState(); - const [latestGasData, setLatestGasData] = useState(); - useEffect(() => { - if (!ethFeed || !gasFeed) { - return; - } - - const readData = async () => { - const [priceData, gasData] = await Promise.all([ - ethFeed.latestRoundData(), - await gasFeed.latestRoundData(), - ]); - setLatestPriceData(priceData); - setLatestGasData(gasData); - }; - readData(); - }, [ethFeed, gasFeed]); + const latestPriceData = useETHUSDRawOracle(provider, "latest"); const [latestPrice, latestPriceTimestamp] = useMemo(() => { if (!latestPriceData) { return [undefined, undefined]; @@ -65,6 +35,7 @@ const PriceBox: React.FC = () => { return [formattedPrice, timestamp]; }, [latestPriceData]); + const latestGasData = useFastGasRawOracle(provider, "latest"); const [latestGasPrice, latestGasPriceTimestamp] = useMemo(() => { if (!latestGasData) { return [undefined, undefined]; diff --git a/src/usePriceOracle.ts b/src/usePriceOracle.ts index 783d76e..1956a52 100644 --- a/src/usePriceOracle.ts +++ b/src/usePriceOracle.ts @@ -79,20 +79,32 @@ const ethUSDFetcherKey = (blockTag: BlockTag | undefined) => { const ethUSDFetcher = ( provider: JsonRpcProvider | undefined - ): Fetcher => + ): Fetcher => async (_, blockTag) => { if (provider?.network.chainId !== 1) { return undefined; } const c = new Contract("eth-usd.data.eth", AggregatorV3Interface, provider); const priceData = await c.latestRoundData({ blockTag }); - return BigNumber.from(priceData.answer); + return priceData; }; export const useETHUSDOracle = ( provider: JsonRpcProvider | undefined, blockTag: BlockTag | undefined ): BigNumber | undefined => { + const fetcher = ethUSDFetcher(provider); + const { data, error } = useSWRImmutable(ethUSDFetcherKey(blockTag), fetcher); + if (error) { + return undefined; + } + return data !== undefined ? BigNumber.from(data.answer) : undefined; +}; + +export const useETHUSDRawOracle = ( + provider: JsonRpcProvider | undefined, + blockTag: BlockTag | undefined +): any | undefined => { const fetcher = ethUSDFetcher(provider); const { data, error } = useSWRImmutable(ethUSDFetcherKey(blockTag), fetcher); if (error) { @@ -100,3 +112,39 @@ export const useETHUSDOracle = ( } return data; }; + +const fastGasFetcherKey = (blockTag: BlockTag | undefined) => { + if (blockTag === undefined) { + return null; + } + return ["gasgwei", blockTag]; +}; + +const fastGasFetcher = + ( + provider: JsonRpcProvider | undefined + ): Fetcher => + async (_, blockTag) => { + if (provider?.network.chainId !== 1) { + return undefined; + } + const c = new Contract( + "fast-gas-gwei.data.eth", + AggregatorV3Interface, + provider + ); + const priceData = await c.latestRoundData({ blockTag }); + return priceData; + }; + +export const useFastGasRawOracle = ( + provider: JsonRpcProvider | undefined, + blockTag: BlockTag | undefined +): any | undefined => { + const fetcher = fastGasFetcher(provider); + const { data, error } = useSWRImmutable(fastGasFetcherKey(blockTag), fetcher); + if (error) { + return undefined; + } + return data; +};