diff --git a/.gitignore b/.gitignore index 8692cf6..3bc7764 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* + +.vscode/* \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 23fd35f..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "editor.formatOnSave": true -} \ No newline at end of file diff --git a/package.json b/package.json index 1bdcb08..50b03bd 100644 --- a/package.json +++ b/package.json @@ -89,5 +89,8 @@ "last 1 safari version" ] }, - "license": "GPL-3.0-or-later" + "license": "GPL-3.0-or-later", + "dependencies": { + "react-google-charts": "^4.0.0" + } } diff --git a/src/apollo/client.js b/src/apollo/client.js index c4e74a2..907ef7e 100644 --- a/src/apollo/client.js +++ b/src/apollo/client.js @@ -10,6 +10,14 @@ export const client = new ApolloClient({ shouldBatch: true, }) +export const v2Client = new ApolloClient({ + link: new HttpLink({ + uri: 'https://api.thegraph.com/subgraphs/name/voltfinance/voltage-exchange-v2', + }), + cache: new InMemoryCache(), + shouldBatch: true, +}) + export const healthClient = new ApolloClient({ link: new HttpLink({ uri: 'https://api.thegraph.com/index-node/graphql', @@ -34,9 +42,31 @@ export const stakingClient = new ApolloClient({ shouldBatch: true, }) +export const barClient = new ApolloClient({ + link: new HttpLink({ + uri: 'https://api.thegraph.com/subgraphs/name/t0mcr8se/voltbar', + }), + cache: new InMemoryCache(), + shouldBatch: true, +}) + export const blockClient = new ApolloClient({ link: new HttpLink({ uri: 'https://api.thegraph.com/subgraphs/name/fuseio/fuse-blocks', }), cache: new InMemoryCache(), }) + +export const stableswapClient = new ApolloClient({ + link: new HttpLink({ + uri: 'https://api.thegraph.com/subgraphs/name/t0mcr8se/stableswap-subgraph', + }), + cache: new InMemoryCache(), +}) + +export const fusdClient = new ApolloClient({ + link: new HttpLink({ + uri: 'https://api.thegraph.com/subgraphs/name/voltfinance/fusd-subgraph', + }), + cache: new InMemoryCache(), +}) diff --git a/src/apollo/queries.js b/src/apollo/queries.js index 6375ec6..c414368 100644 --- a/src/apollo/queries.js +++ b/src/apollo/queries.js @@ -64,8 +64,9 @@ export const GET_BLOCK = gql` export const GET_BLOCKS = (timestamps) => { let queryString = 'query blocks {' queryString += timestamps.map((timestamp) => { - return `t${timestamp}:blocks(first: 1, orderBy: timestamp, orderDirection: desc, where: { timestamp_gt: ${timestamp}, timestamp_lt: ${timestamp + 600 - } }) { + return `t${timestamp}:blocks(first: 1, orderBy: timestamp, orderDirection: desc, where: { timestamp_gt: ${timestamp}, timestamp_lt: ${ + timestamp + 600 + } }) { number }` }) @@ -450,6 +451,21 @@ export const GLOBAL_DATA = (block) => { return gql(queryString) } +export const GLOBAL_DATA_V2 = gql` +query uniswapFactories { + uniswapFactories(where: { id: "${FACTORY_ADDRESS}" }) { + id + totalVolumeUSD + totalVolumeETH + untrackedVolumeUSD + totalLiquidityUSD + totalLiquidityETH + txCount + pairCount + } +} +` + export const GLOBAL_TXNS = gql` query transactions { transactions(first: 100, orderBy: timestamp, orderDirection: desc) { @@ -532,6 +548,58 @@ export const ALL_TOKENS = gql` } ` +export const BAR_QUERY = gql` + query bar { + bars(first: 1) { + id + ratio + totalSupply + voltStaked + } + histories(first: 1000, orderBy: id, orderDirection: desc) { + id + date + voltStaked + ratio + } + voltBalanceHistories(first: 1000, orderBy: id, orderDirection: desc) { + id + totalVoltStaked + } + } +` + +export const STABLESWAP_DATA = gql` + { + systemInfos(first: 5) { + id + exchangeCount + swapCount + tokenCount + } + swaps(first: 5) { + id + address + numTokens + lpTokenSupply + virtualPrice + cumulativeVolume + tokens { + id + } + } + dailyVolumes(first: 1000, orderBy: timestamp, orderDirection: desc) { + id + swap { + id + } + timestamp + lpTokenSupply + volume + } + } +` + export const TOKEN_SEARCH = gql` query tokens($value: String, $id: String) { asSymbol: tokens(where: { symbol_contains: $value }, orderBy: totalLiquidity, orderDirection: desc) { @@ -859,3 +927,30 @@ export const FILTERED_TRANSACTIONS = gql` } } ` + +export const FUSD_DATA = gql` + { + massetDayDatas(first: 1000, orderBy: id, orderDirection: desc) { + id + totalSupply + dailyRedeemAmount + dailySwapAmount + dailyMintAmount + } + massets(first: 10) { + id + totalSupply { + simple + } + cumulativeRedeemed { + simple + } + cumulativeMinted { + simple + } + cumulativeSwapped { + simple + } + } + } +` diff --git a/src/components/GlobalChart/index.js b/src/components/GlobalChart/index.js index 6fa0dc2..70f910a 100644 --- a/src/components/GlobalChart/index.js +++ b/src/components/GlobalChart/index.js @@ -4,55 +4,56 @@ import { timeframeOptions } from '../../constants' import { useGlobalChartData, useGlobalData } from '../../contexts/GlobalData' import { useMedia } from 'react-use' import DropdownSelect from '../DropdownSelect' -import TradingViewChart, { CHART_TYPES } from '../TradingviewChart' -import { RowFixed } from '../Row' -import { OptionButton } from '../ButtonStyled' -import { getTimeframe } from '../../utils' -import { TYPE } from '../../Theme' +import TradingViewChartArea from '../TradingviewChart/area' +import { formattedNum, getTimeframe } from '../../utils' +import { useFormattedDatas } from '../../hooks/useFormattedDatas' -const CHART_VIEW = { +export const CHART_VIEW = { VOLUME: 'Volume', LIQUIDITY: 'Liquidity', + BAR: 'Bar', + TREASURY: 'Treasury', + REVENUE: 'Revenue', } -const VOLUME_WINDOW = { - WEEKLY: 'WEEKLY', - DAYS: 'DAYS', -} -const GlobalChart = ({ display }) => { +// const VOLUME_WINDOW = { +// WEEKLY: 'WEEKLY', +// DAYS: 'DAYS', +// } +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export default function GlobalChart({ view }) { // chart options - const [chartView, setChartView] = useState(display === 'volume' ? CHART_VIEW.VOLUME : CHART_VIEW.LIQUIDITY) + const [chartView, setChartView] = useState(view) + + const timeWindow = timeframeOptions.SIX_MONTHS - // time window and window size for chart - const timeWindow = timeframeOptions.ALL_TIME - const [volumeWindow, setVolumeWindow] = useState(VOLUME_WINDOW.DAYS) + const [dexDailyData] = useGlobalChartData() + const { + volumeChangeUSD, + liquidityChangeUSD, + totalProtocolLiquidityUSD, + stableswapData, + fusdData, + totalVolumeUSD, + xvoltData, + } = useGlobalData() + const allRatios = xvoltData?.histories + const stablesTvl = useFormattedDatas( + [fusdData.massetDayDatas, Object.values(stableswapData.histories)[0], Object.values(stableswapData.histories)[1]], + ['totalSupply', 'supplyFormatted', 'supplyFormatted'], + getTimeframe(timeWindow), + false, + true + ) - // global historical data - const [dailyData, weeklyData] = useGlobalChartData() - const { totalLiquidityUSD, oneDayVolumeUSD, volumeChangeUSD, liquidityChangeUSD, oneWeekVolume, weeklyVolumeChange } = - useGlobalData() + const barChange = useMemo(() => { + if (!allRatios || !allRatios.length > 6) return + return (parseFloat(allRatios[allRatios.length - 1].ratio) - parseFloat(allRatios[allRatios.length - 7].ratio)) * 100 + }, [allRatios]) // based on window, get starttim let utcStartTime = getTimeframe(timeWindow) - const chartDataFiltered = useMemo(() => { - let currentData = volumeWindow === VOLUME_WINDOW.DAYS ? dailyData : weeklyData - return ( - currentData && - Object.keys(currentData) - ?.map((key) => { - let item = currentData[key] - if (item.date > utcStartTime) { - return item - } else { - return - } - }) - .filter((item) => { - return !!item - }) - ) - }, [dailyData, utcStartTime, volumeWindow, weeklyData]) const below800 = useMedia('(max-width: 800px)') // update the width on a window resize @@ -70,67 +71,122 @@ const GlobalChart = ({ display }) => { return () => window.removeEventListener('resize', handleResize) }, [isClient, width]) // Empty array ensures that effect is only run on mount and unmount - return chartDataFiltered ? ( + return dexDailyData ? ( <> {below800 && ( )} - - {chartDataFiltered && chartView === CHART_VIEW.LIQUIDITY && ( + {dexDailyData && stablesTvl && xvoltData && chartView === CHART_VIEW.LIQUIDITY && ( - + + )} + {dexDailyData && chartView === CHART_VIEW.VOLUME && ( + + )} - {chartDataFiltered && chartView === CHART_VIEW.VOLUME && ( + {allRatios && chartView === CHART_VIEW.BAR && ( - formattedNum(num)} + startTime={utcStartTime} /> )} - {display === 'volume' && ( - - setVolumeWindow(VOLUME_WINDOW.DAYS)} - > - D - - setVolumeWindow(VOLUME_WINDOW.WEEKLY)} - > - W - - + {dexDailyData && chartView === CHART_VIEW.REVENUE && ( + + formattedNum(num * 0.003, true)} + startTime={utcStartTime} + /> + )} ) : ( '' ) } - -export default GlobalChart diff --git a/src/components/GlobalStats/index.js b/src/components/GlobalStats/index.js index 03ea8b5..280acb3 100644 --- a/src/components/GlobalStats/index.js +++ b/src/components/GlobalStats/index.js @@ -7,6 +7,8 @@ import { formattedNum, localNumber } from '../../utils' import FusePrice from '../UniPrice' import { TYPE } from '../../Theme' +import { useTokenData } from '../../contexts/TokenData' +import { VOLT_ADDRESS } from '../../constants' const Header = styled.div` width: 100%; @@ -29,6 +31,9 @@ export default function GlobalStats() { const { oneDayVolumeUSD, oneDayTxns, pairCount } = useGlobalData() const [ethPrice] = useEthPrice() + const voltPrice = useTokenData(VOLT_ADDRESS)?.priceUSD + const formattedVoltPrice = voltPrice ? formattedNum(voltPrice, true) : '-' + const formattedEthPrice = ethPrice ? formattedNum(ethPrice, true) : '-' const oneDayFees = oneDayVolumeUSD ? formattedNum(oneDayVolumeUSD * 0.003, true) : '' @@ -47,7 +52,7 @@ export default function GlobalStats() { }} style={{ position: 'relative' }} > - FUSE Price: {formattedEthPrice} + VOLT Price: {formattedVoltPrice} FUSE Price: {formattedEthPrice} {showPriceCard && } )} diff --git a/src/components/TradingviewChart/area.js b/src/components/TradingviewChart/area.js new file mode 100644 index 0000000..d4ff79d --- /dev/null +++ b/src/components/TradingviewChart/area.js @@ -0,0 +1,233 @@ +import React, { useState, useEffect, useRef, useMemo } from 'react' +import { createChart } from 'lightweight-charts' +import dayjs from 'dayjs' +import utc from 'dayjs/plugin/utc' +import { formattedNum, getTimeframe } from '../../utils' +import styled from 'styled-components' +import { usePrevious } from 'react-use' +import { Play } from 'react-feather' +import { useDarkModeManager } from '../../contexts/LocalStorage' +import { IconWrapper } from '..' +import { timeframeOptions } from '../../constants' +import { useFormattedDatas } from '../../hooks/useFormattedDatas' + +const CHART_TYPES = { + BAR: 'BAR', + AREA: 'AREA', +} + +const NUMBER_STYLE = { + PERCENTAGE: 'PERCENTAGE', + USD: 'USD', +} + +dayjs.extend(utc) + +const Wrapper = styled.div` + position: relative; +` + +// constant height for charts +const HEIGHT = 300 + +const TradingViewChartArea = ({ + datas, + base, + baseChange, + fields, + title, + width, + useWeekly = false, + accumulate = false, + configs, + formatter = formattedNum, + sumUp = false, + startTime = getTimeframe(timeframeOptions.ALL_TIME), +}) => { + // reference for DOM element to create with chart + const type = CHART_TYPES.AREA + const ref = useRef() + + // pointer to the chart object + const [chartCreated, setChartCreated] = useState(false) + + const formattedSyncedSummedDatas = useFormattedDatas(datas, fields, startTime, accumulate, sumUp) + // adjust the scale based on the type of chart + const topScale = 0.32 + + const [darkMode] = useDarkModeManager() + const textColor = darkMode ? 'white' : 'black' + const previousTheme = usePrevious(darkMode) + + // reset the chart if them switches + useEffect(() => { + if (chartCreated && previousTheme !== darkMode) { + // remove the tooltip element + let tooltip = document.getElementById('tooltip-id' + type) + let node = document.getElementById('test-id' + type) + node.removeChild(tooltip) + chartCreated.resize(0, 0) + setChartCreated() + } + }, [chartCreated, darkMode, previousTheme, type]) + + // if no chart created yet, create one with options and add to DOM manually + useEffect(() => { + if (!chartCreated && formattedSyncedSummedDatas[0]?.length > 0) { + var chart = createChart(ref.current, { + width: width, + height: HEIGHT, + layout: { + backgroundColor: 'transparent', + textColor: textColor, + }, + rightPriceScale: { + scaleMargins: { + top: topScale, + bottom: 0, + }, + borderVisible: false, + }, + timeScale: { + borderVisible: false, + }, + grid: { + horzLines: { + color: 'rgba(197, 203, 206, 0.5)', + visible: false, + }, + vertLines: { + color: 'rgba(197, 203, 206, 0.5)', + visible: false, + }, + }, + crosshair: { + horzLine: { + visible: false, + labelVisible: false, + }, + vertLine: { + visible: true, + style: 0, + width: 2, + color: 'rgba(32, 38, 46, 0.1)', + labelVisible: false, + }, + }, + localization: { + priceFormatter: (val) => formatter(val, true), + }, + }) + + var seriesArr = configs.map((config) => { + return chart.addAreaSeries(config) + }) + + seriesArr.map((ser, i) => { + ser.setData(formattedSyncedSummedDatas[i]) + }) + + var toolTip = document.createElement('div') + toolTip.setAttribute('id', 'tooltip-id' + type) + toolTip.className = darkMode ? 'three-line-legend-dark' : 'three-line-legend' + ref.current.appendChild(toolTip) + toolTip.style.display = 'block' + toolTip.style.fontWeight = '500' + toolTip.style.left = -4 + 'px' + toolTip.style.top = '-' + 8 + 'px' + toolTip.style.backgroundColor = 'transparent' + + // format numbers + let percentChange = baseChange?.toFixed(2) + let formattedPercentChange = (percentChange > 0 ? '+' : '') + percentChange + '%' + let color = percentChange >= 0 ? 'green' : 'red' + + // get the title of the chart + function setLastBarText() { + toolTip.innerHTML = + `
${title}
` + + `
` + + formatter(base ?? formattedSyncedSummedDatas[0][formattedSyncedSummedDatas[0].length - 1].value, true) + + `${formattedPercentChange}` + + '
' + } + setLastBarText() + + // update the title when hovering on the chart + chart.subscribeCrosshairMove(function (param) { + if ( + param === undefined || + param.time === undefined || + param.point.x < 0 || + param.point.x > width || + param.point.y < 0 || + param.point.y > HEIGHT + ) { + setLastBarText() + } else { + let dateStr = useWeekly + ? dayjs(param.time.year + '-' + param.time.month + '-' + param.time.day) + .startOf('week') + .format('MMMM D, YYYY') + + '-' + + dayjs(param.time.year + '-' + param.time.month + '-' + param.time.day) + .endOf('week') + .format('MMMM D, YYYY') + : dayjs(param.time.year + '-' + param.time.month + '-' + param.time.day).format('MMMM D, YYYY') + var prices = seriesArr.map((ser) => param.seriesPrices.get(ser) ?? 0) + var totalPrice = prices.reduce((sum, price) => sum + price, 0) + toolTip.innerHTML = + `
${title}
` + + `
` + + formatter(totalPrice, true) + + '
' + + '
' + + dateStr + + '
' + } + }) + + chart.timeScale().fitContent() + + setChartCreated(chart) + } + }, [ + base, + baseChange, + chartCreated, + configs, + darkMode, + datas, + formattedSyncedSummedDatas, + formatter, + textColor, + title, + topScale, + type, + useWeekly, + width, + ]) + + // responsiveness + useEffect(() => { + if (width) { + chartCreated && chartCreated.resize(width, HEIGHT) + chartCreated && chartCreated.timeScale().scrollToPosition(0) + } + }, [chartCreated, width]) + + return ( + +
+ + { + chartCreated && chartCreated.timeScale().fitContent() + }} + /> + + + ) +} + +export default TradingViewChartArea diff --git a/src/components/TradingviewChart/index.js b/src/components/TradingviewChart/bars.js similarity index 87% rename from src/components/TradingviewChart/index.js rename to src/components/TradingviewChart/bars.js index 767f426..67024a5 100644 --- a/src/components/TradingviewChart/index.js +++ b/src/components/TradingviewChart/bars.js @@ -8,10 +8,9 @@ import { usePrevious } from 'react-use' import { Play } from 'react-feather' import { useDarkModeManager } from '../../contexts/LocalStorage' import { IconWrapper } from '..' - dayjs.extend(utc) -export const CHART_TYPES = { +const CHART_TYPES = { BAR: 'BAR', AREA: 'AREA', } @@ -23,17 +22,9 @@ const Wrapper = styled.div` // constant height for charts const HEIGHT = 300 -const TradingViewChart = ({ - type = CHART_TYPES.BAR, - data, - base, - baseChange, - field, - title, - width, - useWeekly = false, -}) => { +const TradingViewChartBar = ({ data, base, baseChange, field, title, width, useWeekly = false }) => { // reference for DOM element to create with chart + const type = CHART_TYPES.BAR const ref = useRef() // pointer to the chart object @@ -41,7 +32,7 @@ const TradingViewChart = ({ const dataPrev = usePrevious(data) useEffect(() => { - if (data !== dataPrev && chartCreated && type === CHART_TYPES.BAR) { + if (data !== dataPrev && chartCreated) { // remove the tooltip element let tooltip = document.getElementById('tooltip-id' + type) let node = document.getElementById('test-id' + type) @@ -60,7 +51,7 @@ const TradingViewChart = ({ }) // adjust the scale based on the type of chart - const topScale = type === CHART_TYPES.AREA ? 0.32 : 0.2 + const topScale = 0.2 const [darkMode] = useDarkModeManager() const textColor = darkMode ? 'white' : 'black' @@ -126,26 +117,18 @@ const TradingViewChart = ({ }, }) - var series = - type === CHART_TYPES.BAR - ? chart.addHistogramSeries({ - color: '#5ED73E', - priceFormat: { - type: 'volume', - }, - scaleMargins: { - top: 0.32, - bottom: 0, - }, - lineColor: '#5ED73E', - lineWidth: 3, - }) - : chart.addAreaSeries({ - topColor: '#5ED73E', - bottomColor: 'rgba(255, 255, 255, 0)', - lineColor: '#5ED73E', - lineWidth: 3, - }) + var series = chart.addHistogramSeries({ + color: '#5ED73E', + priceFormat: { + type: 'volume', + }, + scaleMargins: { + top: topScale, + bottom: 0, + }, + lineColor: '#5ED73E', + lineWidth: 3, + }) series.setData(formattedData) var toolTip = document.createElement('div') @@ -251,4 +234,4 @@ const TradingViewChart = ({ ) } -export default TradingViewChart +export default TradingViewChartBar diff --git a/src/constants/index.js b/src/constants/index.js index c5b72a3..677d5a9 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -11,6 +11,7 @@ export const timeframeOptions = { MONTH: '1 month', // THREE_MONTHS: '3 months', // YEAR: '1 year', + SIX_MONTHS: '6 months', ALL_TIME: 'All time', } @@ -34,3 +35,10 @@ export const PAIR_BLACKLIST = ['0xb6a741f37d6e455ebcc9f17e2c16d0586c3f57a5'] * For tokens that cause erros on fee calculations */ export const FEE_WARNING_TOKENS = ['0xd46ba6d942050d489dbd938a2c909a5d5039a161'] + +export const VOLT_ADDRESS = '0x34ef2cc892a88415e9f02b91bfa9c91fc0be6bd4' +export const WFUSE_ADDRESS = '0x0be9e53fd7edac9f859882afdda116645287c629' + +export const TREASURY1 = '0x03709784c96aeaAa9Dd38Df14A23e996681b2C66' +export const TREASURY2 = '0xBdA5aDc17136b3f8e10e9Bd101A979ceAB4FBa45' +export const TREASURY3 = '0x57bAaaD96BA5Fca62c7eD3938FC3bc5295eBf348' diff --git a/src/contexts/GlobalData.js b/src/contexts/GlobalData.js index 7035e5b..0da9dc1 100644 --- a/src/contexts/GlobalData.js +++ b/src/contexts/GlobalData.js @@ -1,5 +1,5 @@ import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect, useState } from 'react' -import { client } from '../apollo/client' +import { barClient, client, fusdClient, stableswapClient } from '../apollo/client' import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' import { useTimeframe } from './Application' @@ -18,9 +18,15 @@ import { ALL_PAIRS, ALL_TOKENS, TOP_LPS_PER_PAIRS, + STABLESWAP_DATA, + FUSD_DATA, + BAR_QUERY, } from '../apollo/queries' import weekOfYear from 'dayjs/plugin/weekOfYear' +import { VOLT_ADDRESS } from '../constants' import { useAllPairData } from './PairData' +import { formatEther } from 'ethers/utils' +import { getTokenData } from './TokenData' const UPDATE = 'UPDATE' const UPDATE_TXNS = 'UPDATE_TXNS' const UPDATE_CHART = 'UPDATE_CHART' @@ -28,7 +34,10 @@ const UPDATE_ETH_PRICE = 'UPDATE_ETH_PRICE' const ETH_PRICE_KEY = 'ETH_PRICE_KEY' const UPDATE_ALL_PAIRS_IN_UNISWAP = 'UPDAUPDATE_ALL_PAIRS_IN_UNISWAPTE_TOP_PAIRS' const UPDATE_ALL_TOKENS_IN_UNISWAP = 'UPDATE_ALL_TOKENS_IN_UNISWAP' +const UPDATE_ALL_RATIOS = 'UPDATE_ALL_RATIOS' const UPDATE_TOP_LPS = 'UPDATE_TOP_LPS' +const UPDATE_STABLESWAP_DATA = 'UPDATE_STABLESWAP_DATA' +const UPDATE_FUSD_DATA = 'UPDATE_FUSD_DATA' // format dayjs with the libraries that we need dayjs.extend(utc) @@ -91,6 +100,14 @@ function reducer(state, { type, payload }) { } } + case UPDATE_ALL_RATIOS: { + const { allRatios } = payload + return { + ...state, + allRatios, + } + } + case UPDATE_TOP_LPS: { const { topLps } = payload return { @@ -98,6 +115,23 @@ function reducer(state, { type, payload }) { topLps, } } + + case UPDATE_STABLESWAP_DATA: { + const { stableswapData } = payload + return { + ...state, + stableswapData, + } + } + + case UPDATE_FUSD_DATA: { + const { fusdData } = payload + return { + ...state, + fusdData, + } + } + default: { throw Error(`Unexpected action type in DataContext reducer: '${type}'.`) } @@ -171,6 +205,34 @@ export default function Provider({ children }) { }, }) }, []) + + const updateAllBarRatios = useCallback((allRatios) => { + dispatch({ + type: UPDATE_ALL_RATIOS, + payload: { + allRatios, + }, + }) + }, []) + + const updateStableSwapData = useCallback((stableswapData) => { + dispatch({ + type: UPDATE_STABLESWAP_DATA, + payload: { + stableswapData, + }, + }) + }, []) + + const updateFusdData = useCallback((fusdData) => { + dispatch({ + type: UPDATE_FUSD_DATA, + payload: { + fusdData, + }, + }) + }, []) + return ( @@ -203,6 +271,147 @@ export default function Provider({ children }) { ) } +async function getFusdData() { + try { + let data = await fusdClient.query({ + query: FUSD_DATA, + fetchPolicy: 'cache-first', + }) + return data.data + } catch (e) { + console.log(e) + } +} + +/** + * Gets all the global data for the overview page. + * Needs current eth price and the old eth price to get + * 24 hour USD changes. + * @param {*} ethPrice + * @param {*} oldEthPrice + */ +// TODO: refactor this to use exchange-v2 and to get the data in a single call +async function getGlobalDataV2(ethPrice, oldEthPrice) { + // data for each day , historic data used for % changes + let data = {} + let oneDayData = {} + let twoDayData = {} + + try { + // get timestamps for the days + const utcCurrentTime = dayjs() + const utcOneDayBack = utcCurrentTime.subtract(1, 'day').unix() + const utcTwoDaysBack = utcCurrentTime.subtract(2, 'day').unix() + const utcOneWeekBack = utcCurrentTime.subtract(1, 'week').unix() + const utcTwoWeeksBack = utcCurrentTime.subtract(2, 'week').unix() + + // get the blocks needed for time travel queries + let [oneDayBlock, twoDayBlock, oneWeekBlock, twoWeekBlock] = await getBlocksFromTimestamps([ + utcOneDayBack, + utcTwoDaysBack, + utcOneWeekBack, + utcTwoWeeksBack, + ]) + + let stableswapRes = await stableswapClient.query({}) + // fetch the global data + let result = await client.query({ + query: GLOBAL_DATA(), + fetchPolicy: 'cache-first', + }) + data = result.data.uniswapFactories[0] + + // fetch the historical data + let oneDayResult = await client.query({ + query: GLOBAL_DATA(oneDayBlock?.number), + fetchPolicy: 'cache-first', + }) + oneDayData = oneDayResult.data.uniswapFactories[0] + + let twoDayResult = await client.query({ + query: GLOBAL_DATA(twoDayBlock?.number), + fetchPolicy: 'cache-first', + }) + twoDayData = twoDayResult.data.uniswapFactories[0] + + let oneWeekResult = await client.query({ + query: GLOBAL_DATA(oneWeekBlock?.number), + fetchPolicy: 'cache-first', + }) + const oneWeekData = oneWeekResult.data.uniswapFactories[0] + + let twoWeekResult = await client.query({ + query: GLOBAL_DATA(twoWeekBlock?.number), + fetchPolicy: 'cache-first', + }) + const twoWeekData = twoWeekResult.data.uniswapFactories[0] + + if (data && oneDayData && twoDayData && twoWeekData) { + let [oneDayVolumeUSD, volumeChangeUSD] = get2DayPercentChange( + data.totalVolumeUSD, + oneDayData.totalVolumeUSD ? oneDayData.totalVolumeUSD : 0, + twoDayData.totalVolumeUSD ? twoDayData.totalVolumeUSD : 0 + ) + + const [oneWeekVolume, weeklyVolumeChange] = get2DayPercentChange( + data.totalVolumeUSD, + oneWeekData.totalVolumeUSD, + twoWeekData.totalVolumeUSD + ) + + const [oneDayTxns, txnChange] = get2DayPercentChange( + data.txCount, + oneDayData.txCount ? oneDayData.txCount : 0, + twoDayData.txCount ? twoDayData.txCount : 0 + ) + + // format the total liquidity in USD + data.totalLiquidityUSD = data.totalLiquidityETH * ethPrice + const liquidityChangeUSD = getPercentChange( + data.totalLiquidityETH * ethPrice, + oneDayData.totalLiquidityETH * oldEthPrice + ) + + // add relevant fields with the calculated amounts + data.oneDayVolumeUSD = oneDayVolumeUSD + data.oneWeekVolume = oneWeekVolume + data.weeklyVolumeChange = weeklyVolumeChange + data.volumeChangeUSD = volumeChangeUSD + data.liquidityChangeUSD = liquidityChangeUSD + data.oneDayTxns = oneDayTxns + data.txnChange = txnChange + } + } catch (e) { + console.log(e) + } + + return data +} + +export async function fetchFormatStableswapData() { + let stableswapData = await getStableswapData() + if (!stableswapData) return + let stableswapHistory = { + [stableswapData?.swaps?.[0]?.id]: stableswapData?.dailyVolumes + ?.filter((dayData) => dayData?.swap?.id === stableswapData?.swaps?.[0]?.id) + .map((dayData) => { + return { ...dayData, supplyFormatted: formatEther(dayData.lpTokenSupply), date: dayData.timestamp } + }) + .reverse(), + [stableswapData?.swaps?.[1]?.id]: stableswapData?.dailyVolumes + ?.filter((dayData) => dayData?.swap?.id === stableswapData?.swaps?.[1]?.id) + .map((dayData) => { + return { ...dayData, supplyFormatted: formatEther(dayData.lpTokenSupply), date: dayData.timestamp } + }) + .reverse(), + } + + return { + ...stableswapData, + histories: stableswapHistory, + } +} + /** * Gets all the global data for the overview page. * Needs current eth price and the old eth price to get @@ -232,6 +441,11 @@ async function getGlobalData(ethPrice, oldEthPrice) { utcTwoWeeksBack, ]) + let stableswapData = await fetchFormatStableswapData() + let fusdData = await getFusdData() + let xvoltData = await getAllBarRatios() + let voltData = await getTokenData(VOLT_ADDRESS) + // fetch the global data let result = await client.query({ query: GLOBAL_DATA(), @@ -298,6 +512,58 @@ async function getGlobalData(ethPrice, oldEthPrice) { data.liquidityChangeUSD = liquidityChangeUSD data.oneDayTxns = oneDayTxns data.txnChange = txnChange + data.stableswapLiquidityUSD = + parseFloat(formatEther(stableswapData.swaps[1].lpTokenSupply)) + + parseFloat(formatEther(stableswapData.swaps[0].lpTokenSupply)) + data.fusdLiquidityUSD = parseFloat(fusdData?.massets?.[0]?.totalSupply?.simple) + + data.voltPrice = voltData.derivedETH * ethPrice + + data.totalProtocolLiquidityUSD = + parseFloat(data.totalLiquidityUSD) + + data.stableswapLiquidityUSD + + data.fusdLiquidityUSD + + parseFloat(xvoltData.bars[0].voltStaked) * data.voltPrice + data.totalVolumeUSD = [ + data.totalVolumeUSD, + stableswapData.swaps[0].cumulativeVolume, + stableswapData.swaps[1].cumulativeVolume, + fusdData.massets[0].cumulativeMinted.simple, + fusdData.massets[0].cumulativeRedeemed.simple, + fusdData.massets[0].cumulativeSwapped.simple, + ].reduce((a, b) => parseFloat(a) + parseFloat(b), 0) + data.xvoltData = { + ...xvoltData, + histories: xvoltData.histories + .map((history, i) => { + return { + ...history, + dayStakedUSD: history.voltStaked * data.voltPrice, + totalStakedUSD: xvoltData.voltBalanceHistories[i].totalVoltStaked * data.voltPrice, + } + }) + .reverse(), + } + data.fusdData = { + ...fusdData, + massetDayDatas: fusdData?.massetDayDatas + ?.map((dayData) => { + return { + id: dayData.id, + totalSupply: parseFloat(formatEther(dayData.totalSupply)), + dailyRedeemAmount: parseFloat(formatEther(dayData.dailyRedeemAmount)), + dailySwapAmount: parseFloat(formatEther(dayData.dailySwapAmount)), + dailyMintAmount: parseFloat(formatEther(dayData.dailyMintAmount)), + dailyVolume: + parseFloat(formatEther(dayData.dailySwapAmount)) + + parseFloat(formatEther(dayData.dailyMintAmount)) + + parseFloat(formatEther(dayData.dailyRedeemAmount)), + date: dayData.id * 24 * 60 * 60, + } + }) + .reverse(), + } + data.stableswapData = stableswapData } } catch (e) { console.log(e) @@ -525,11 +791,38 @@ async function getAllTokensOnUniswap() { } } +async function getAllBarRatios() { + try { + let result = await barClient.query({ + query: BAR_QUERY, + fetchPolicy: 'cache-first', + }) + return result?.data + } catch (e) { + console.log(e) + } +} + +async function getStableswapData() { + try { + let result = await stableswapClient.query({ + query: STABLESWAP_DATA, + fetchPolicy: 'cache-first', + }) + return result?.data + } catch (e) { + console.log(e) + } +} + /** * Hook that fetches overview data, plus all tokens and pairs for search */ export function useGlobalData() { - const [state, { update, updateAllPairsInUniswap, updateAllTokensInUniswap }] = useGlobalDataContext() + const [ + state, + { update, updateAllPairsInUniswap, updateAllTokensInUniswap, updateStableSwapData }, + ] = useGlobalDataContext() const [ethPrice, oldEthPrice] = useEthPrice() const data = state?.globalData @@ -539,20 +832,70 @@ export function useGlobalData() { let globalData = await getGlobalData(ethPrice, oldEthPrice) globalData && update(globalData) - let allPairs = await getAllPairsOnUniswap() - updateAllPairsInUniswap(allPairs) + // let allPairs = await getAllPairsOnUniswap() + // updateAllPairsInUniswap(allPairs) - let allTokens = await getAllTokensOnUniswap() - updateAllTokensInUniswap(allTokens) + // let allTokens = await getAllTokensOnUniswap() + // updateAllTokensInUniswap(allTokens) } if (!data && ethPrice && oldEthPrice) { fetchData() } - }, [ethPrice, oldEthPrice, update, data, updateAllPairsInUniswap, updateAllTokensInUniswap]) + }, [ethPrice, oldEthPrice, update, data, updateAllPairsInUniswap, updateAllTokensInUniswap, updateStableSwapData]) return data || {} } +// export function useBarAllRatios() { +// const [state, { updateAllBarRatios }] = useGlobalDataContext() +// const allRatios = state?.allRatios +// useEffect(() => { +// if (allRatios) return +// async function fetchData() { +// let allBarRatios = await getAllBarRatios()?.histories +// updateAllBarRatios(allBarRatios) +// } +// fetchData() +// }, [allRatios, updateAllBarRatios]) +// return allRatios +// } + +export function useFusdData() { + const [state, { updateFusdData }] = useGlobalDataContext() + const fusdData = state?.fusdData + useEffect(() => { + if (fusdData) return + async function fetchData() { + let fusdDataRes = await getFusdData() + updateFusdData(fusdDataRes) + } + fetchData() + }, [fusdData, updateFusdData]) + return fusdData +} + +export function useStableswapData() { + const [state, { updateStableSwapData }] = useGlobalDataContext() + const stableswapData = state?.stableswapData + useEffect(() => { + if (stableswapData) return + async function fetchData() { + let stableswapDataRes = await fetchFormatStableswapData() + updateStableSwapData(stableswapDataRes) + } + fetchData() + }, [stableswapData, updateStableSwapData]) + return useMemo(() => { + if (!stableswapData) return + + // sum up liquidity and volume of both stableswapData.histories + + return { ...stableswapData } + + return stableswapData + }, [stableswapData]) +} + export function useGlobalChartData() { const [state, { updateChart }] = useGlobalDataContext() const [oldestDateFetch, setOldestDateFetched] = useState() @@ -642,7 +985,7 @@ export function useAllTokensInUniswap() { * Get the top liquidity positions based on USD size * @TODO Not a perfect lookup needs improvement */ -export function useTopLps() { +export function useTopLps(sortBy = 'usd') { const [state, { updateTopLps }] = useGlobalDataContext() let topLps = state?.topLps @@ -675,13 +1018,12 @@ export function useTopLps() { ) // get the top lps from the results formatted - const topLps = [] - topLpLists + const topLps = topLpLists .filter((i) => !!i) // check for ones not fetched correctly .map((list) => { return list.map((entry) => { const pairData = allPairs[entry.pair.id] - return topLps.push({ + return { user: entry.user, pairName: pairData.token0.symbol + '-' + pairData.token1.symbol, pairAddress: entry.pair.id, @@ -690,13 +1032,19 @@ export function useTopLps() { usd: (parseFloat(entry.liquidityTokenBalance) / parseFloat(pairData.totalSupply)) * parseFloat(pairData.reserveUSD), - }) + volumeUSD: parseFloat(pairData.volumeUSD), + txCount: parseFloat(pairData.txCount), + oneDayVolumeUSD: parseFloat(pairData.oneDayVolumeUSD), + oneWeekVolumeUSD: parseFloat(pairData.oneWeekVolumeUSD), + } }) }) + .sort((a, b) => (a[sortBy] > b[sortBy] ? -1 : 1)) + .splice(0, 100) - const sorted = topLps.sort((a, b) => (a.usd > b.usd ? -1 : 1)) - const shorter = sorted.splice(0, 100) - updateTopLps(shorter) + // const sorted = topLps.sort((a, b) => (a[sortBy] > b[sortBy] ? -1 : 1)) + // const shorter = sorted.splice(0, 100) + updateTopLps(topLps) } if (!topLps && allPairs && Object.keys(allPairs).length > 0) { diff --git a/src/contexts/TokenData.js b/src/contexts/TokenData.js index 8454884..672dc62 100644 --- a/src/contexts/TokenData.js +++ b/src/contexts/TokenData.js @@ -317,7 +317,7 @@ const getTopTokens = async (ethPrice, ethPriceOld) => { } } -const getTokenData = async (address, ethPrice, ethPriceOld) => { +export const getTokenData = async (address, ethPrice, ethPriceOld) => { const utcCurrentTime = dayjs() const utcOneDayBack = utcCurrentTime.subtract(1, 'day').startOf('minute').unix() const utcTwoDaysBack = utcCurrentTime.subtract(2, 'day').startOf('minute').unix() diff --git a/src/hooks/useAccountPositionValue.ts b/src/hooks/useAccountPositionValue.ts new file mode 100644 index 0000000..4abfa85 --- /dev/null +++ b/src/hooks/useAccountPositionValue.ts @@ -0,0 +1,102 @@ +import { AddressZero } from 'ethers/constants' +import { useEffect, useMemo, useState } from 'react' +import { VOLT_ADDRESS, WFUSE_ADDRESS } from '../constants' +import { useUserPositions } from '../contexts/User' + +enum Status { + NOT_REQUESTED, + LOADING, + SUCCESS, + ERROR, +} + +export function useAccountPositionValue(account: string) { + const positions = useUserPositions(account.toLowerCase()) + + const aggregateFees = useMemo(() => { + return positions?.reduce(function (total, position) { + return total + position.fees.sum + }, 0) + }, [positions]) + + const positionValue = useMemo(() => { + return positions + ? positions.reduce((total, position) => { + return ( + total + + (parseFloat(position?.liquidityTokenBalance) / parseFloat(position?.pair?.totalSupply)) * + position?.pair?.reserveUSD + ) + }, 0) + : null + }, [positions]) + return { fees: aggregateFees, positionValue, positions } +} + +export function useTreasuryHoldings(account: string) { + const { resp, status } = useSafeCgwBalance(account) + const { positions, positionValue } = useAccountPositionValue(account) + + return useMemo(() => { + if (!resp || !positions || status !== Status.SUCCESS) { + return { status: Status.LOADING, resp } + } + + const { fiatTotal, items: tokenBalances } = resp + + const volt = parseFloat( + tokenBalances.find((token) => token.tokenInfo.address.toLowerCase() === VOLT_ADDRESS)?.fiatBalance ?? 0 + ) + const fuse = tokenBalances + .filter( + (token) => + token.tokenInfo.address.toLowerCase() === WFUSE_ADDRESS || + token.tokenInfo.address.toLowerCase() === AddressZero + ) + .reduce((acc, token) => acc + parseFloat(token.fiatBalance), 0) + const lps = positionValue + const stables = tokenBalances + .filter((token) => token.tokenInfo.symbol.toLowerCase().includes('usd')) // TODO: filter by addresses not symbols + .reduce((acc, token) => acc + parseFloat(token.fiatBalance), 0) + const other = fiatTotal - volt - fuse - stables + + return { + status, + resp, + fiatTotal: parseFloat(fiatTotal) + lps, + volt, + fuse, + other, + stables, + lps, + } + }, [resp, positions, status, positionValue]) +} + +export function useSafeCgwBalance(account: string) { + const [resp, setResp] = useState(undefined) + + const [status, setStatus] = useState(Status.NOT_REQUESTED) + + useEffect(() => { + if (!account || status !== Status.NOT_REQUESTED) { + return + } + setStatus(Status.LOADING) + async function fetchData() { + try { + const response = await fetch( + `https://gateway.safe.fuse.io/v1/chains/122/safes/${account}/balances/USD?exclude_spam=true&trusted=false` + ) + const json = await response.json() + setResp(json) + setStatus(Status.SUCCESS) + } catch (e) { + console.log(e) + setStatus(Status.ERROR) + } + } + fetchData() + }, [account, status]) + return { resp, status } +} diff --git a/src/hooks/useFormattedDatas.ts b/src/hooks/useFormattedDatas.ts new file mode 100644 index 0000000..7fc2d9d --- /dev/null +++ b/src/hooks/useFormattedDatas.ts @@ -0,0 +1,56 @@ +import dayjs from 'dayjs' +import { useMemo } from 'react' + +export function useFormattedDatas(datas: any, fields: any, startTime: any, accumulate: any, sumFields: any) { + const formattedSyncedDatas = useMemo(() => { + if (!datas || !datas.length) return + const syncedDatas = [] + const filteredDatas = datas + const allTimestamps = filteredDatas.map((data) => [...data.map((day) => day.date)]).flat() + + const firstTimestamp = Math.min(...allTimestamps) + const lastTimestamp = Math.max(...allTimestamps) + let curTimestamp = firstTimestamp + const oneDay = 86400 + const indices = filteredDatas.map((_) => 0) + const prevs = filteredDatas.map((data, i) => parseFloat(data[0][fields[i]])) + const days = [] + while (curTimestamp <= lastTimestamp) { + days.push({ date: curTimestamp, values: [] }) + const syncedData = filteredDatas.map((data, i) => { + if (indices[i] < data.length && data[indices[i]].date <= curTimestamp) { + prevs[i] = parseFloat(data[indices[i]][fields[i]]) + (accumulate ? prevs[i] : 0) + indices[i] += 1 + } + return prevs[i] + }) + syncedDatas.push( + syncedData.map((_syncedData) => { + return { + value: _syncedData, + date: curTimestamp, + time: dayjs.unix(curTimestamp).utc().format('YYYY-MM-DD'), + timestamp: curTimestamp, + } + }) + ) + curTimestamp += oneDay + } + return syncedDatas[0] + .map((_, i) => syncedDatas.map((data) => data[i])) + .map((data) => data.filter((entry) => entry.timestamp >= startTime)) + }, [accumulate, datas, fields, startTime]) + return useMemo(() => { + if (!formattedSyncedDatas || !formattedSyncedDatas.length) return + return sumFields + ? [ + formattedSyncedDatas[0].map((data, i) => { + return { + ...data, + value: formattedSyncedDatas.reduce((acc, points) => acc + parseFloat(points[i].value), 0), + } + }), + ] + : formattedSyncedDatas + }, [formattedSyncedDatas, sumFields]) +} diff --git a/src/pages/GlobalPage.js b/src/pages/GlobalPage.js index a58e9e5..4db1742 100644 --- a/src/pages/GlobalPage.js +++ b/src/pages/GlobalPage.js @@ -1,39 +1,25 @@ -import React, { useEffect } from 'react' +import React, { useEffect, useMemo } from 'react' import { withRouter } from 'react-router-dom' import { Box } from 'rebass' import styled from 'styled-components' +import { Chart } from 'react-google-charts' -import { AutoRow, RowBetween } from '../components/Row' +import { RowBetween } from '../components/Row' import { AutoColumn } from '../components/Column' -import PairList from '../components/PairList' -import TopTokenList from '../components/TokenList' -import TxnList from '../components/TxnList' -import GlobalChart from '../components/GlobalChart' +import GlobalChart, { CHART_VIEW } from '../components/GlobalChart' import Search from '../components/Search' import GlobalStats from '../components/GlobalStats' -import { useGlobalData, useGlobalTransactions } from '../contexts/GlobalData' -import { useAllPairData } from '../contexts/PairData' +import { useGlobalData } from '../contexts/GlobalData' import { useMedia } from 'react-use' import Panel from '../components/Panel' -import { useAllTokenData } from '../contexts/TokenData' import { formattedNum, formattedPercent } from '../utils' import { TYPE, ThemedBackground } from '../Theme' -import { transparentize } from 'polished' -import { CustomLink } from '../components/Link' import { PageWrapper, ContentWrapper } from '../components' - -const ListOptions = styled(AutoRow)` - height: 40px; - width: 100%; - font-size: 1.25rem; - font-weight: 600; - - @media screen and (max-width: 640px) { - font-size: 1rem; - } -` +import { useAllPairData } from '../contexts/PairData' +import { useTreasuryHoldings } from '../hooks/useAccountPositionValue' +import { TREASURY1, TREASURY2, TREASURY3 } from '../constants' const GridRow = styled.div` display: grid; @@ -45,11 +31,96 @@ const GridRow = styled.div` ` function GlobalPage() { - // get data for lists and totals + // Add a volt price next fuse + // Start liquidity from 6 months + // Single volume line for everything + + const treasury1Holdings = useTreasuryHoldings(TREASURY1) + const treasury2Holdings = useTreasuryHoldings(TREASURY2) + const treasury3Holdings = useTreasuryHoldings(TREASURY3) + const fiatTotalTreasuries = useMemo(() => { + if (!treasury1Holdings.fiatTotal || !treasury2Holdings.fiatTotal || !treasury3Holdings.fiatTotal) return 0 + return treasury1Holdings.fiatTotal + treasury2Holdings.fiatTotal + treasury3Holdings.fiatTotal + }, [treasury1Holdings.fiatTotal, treasury2Holdings.fiatTotal, treasury3Holdings.fiatTotal]) + + const { + totalLiquidityUSD, + oneDayVolumeUSD, + volumeChangeUSD, + liquidityChangeUSD, + stableswapLiquidityUSD, + fusdLiquidityUSD, + } = useGlobalData() const allPairs = useAllPairData() - const allTokens = useAllTokenData() - const transactions = useGlobalTransactions() - const { totalLiquidityUSD, oneDayVolumeUSD, volumeChangeUSD, liquidityChangeUSD } = useGlobalData() + + const data = [ + ['Product', 'TVL in $USD'], + ['DEX', totalLiquidityUSD], + ['Stableswap', stableswapLiquidityUSD], + ['FUSD V2', fusdLiquidityUSD], + ['xVOLT', 72000], + ] + const pairsData = [ + ['Product', 'TVL in $USD'], + ...(Object.values(allPairs) + ?.sort((a, b) => b.volumeUSD - a.volumeUSD) + .slice(0, 10) + .map((pair) => [`${pair.token0.symbol}/${pair.token1.symbol}`, parseFloat(pair.volumeUSD)]) || []), + // ...(topLps?.slice(0, 5).map((lp) => [lp.pairName, lp.volumeUSD]) || []), + ] + + const treasuryData = [ + ['Product', `TVL in $USD`], + [ + 'VOLT & xVOLT', + [treasury1Holdings.volt ?? 0, treasury2Holdings.volt ?? 0, treasury3Holdings.volt ?? 0].reduce((a, b) => a + b), + ], + [ + 'Stables & fUSD', + [treasury1Holdings.stables ?? 0, treasury2Holdings.stables ?? 0, treasury3Holdings.stables ?? 0].reduce( + (a, b) => a + b + ), + ], + [ + 'LPs', + [treasury1Holdings.lps ?? 0, treasury2Holdings.lps ?? 0, treasury3Holdings.lps ?? 0].reduce((a, b) => a + b), + ], + [ + 'FUSE', + [treasury1Holdings.fuse ?? 0, treasury2Holdings.fuse ?? 0, treasury3Holdings.fuse ?? 0].reduce((a, b) => a + b), + ], + [ + 'Other', + Math.max( + [treasury1Holdings.other ?? 0, treasury2Holdings.other ?? 0, treasury3Holdings.other ?? 0].reduce( + (a, b) => a + b + ), + 0 + ), + ], + ] + + const pairsOptions = { + title: 'Top 10 Traded Pairs', + pieHole: 0.4, + is3D: false, + backgroundColor: '#DDD', + color: 'white', + } + const options = { + title: 'TVL $USD', + pieHole: 0.4, + is3D: false, + backgroundColor: '#DDD', + color: 'white', + } + const treasuryOptions = { + title: `Voltage Treasury Funds $USD ${formattedNum(fiatTotalTreasuries, true)}`, + pieHole: 0.3, + is3D: true, + backgroundColor: '#DDD', + color: 'white', + } // breakpoints const below800 = useMedia('(max-width: 800px)') @@ -110,47 +181,59 @@ function GlobalPage() { {!below800 && ( - + - + )} {below800 && ( - + )} - - - Top Tokens - See All - - - - - - - - Top Pairs - See All - - - - - - - - - Transactions - - - - - + + + + + + + + + + + + + + + + + +
diff --git a/src/utils/index.js b/src/utils/index.js index 061efef..ba3b927 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -30,6 +30,9 @@ export function getTimeframe(timeWindow) { case timeframeOptions.ALL_TIME: utcStartTime = utcEndTime.subtract(1, 'year').endOf('day').unix() - 1 break + case timeframeOptions.SIX_MONTHS: + utcStartTime = utcEndTime.subtract(6, 'month').endOf('day').unix() - 1 + break default: utcStartTime = utcEndTime.subtract(1, 'year').startOf('year').unix() - 1 break @@ -37,6 +40,27 @@ export function getTimeframe(timeWindow) { return utcStartTime } +export function getTimeframeDay(days) { + const utcEndTime = dayjs.utc() + // based on window, get starttime + return utcEndTime.substract(days, 'day').endOf('day').unix() - 1 + // switch (timeWindow) { + // case timeframeOptions.WEEK: + // utcStartTime = utcEndTime.subtract(1, 'week').endOf('day').unix() - 1 + // break + // case timeframeOptions.MONTH: + // utcStartTime = utcEndTime.subtract(1, 'month').endOf('day').unix() - 1 + // break + // case timeframeOptions.ALL_TIME: + // utcStartTime = utcEndTime.subtract(1, 'year').endOf('day').unix() - 1 + // break + // default: + // utcStartTime = utcEndTime.subtract(1, 'year').startOf('year').unix() - 1 + // break + // } + // return utcStartTime +} + export function getPoolLink(token0Address, token1Address = null, remove = false) { if (!token1Address) { return ( diff --git a/yarn.lock b/yarn.lock index e3b5c97..57bef2a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9852,6 +9852,11 @@ react-ga@^3.1.2: resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-3.1.2.tgz#e13f211c51a2e5c401ea69cf094b9501fe3c51ce" integrity sha512-OJrMqaHEHbodm+XsnjA6ISBEHTwvpFrxco65mctzl/v3CASMSLSyUkFqz9yYrPDKGBUfNQzKCjuMJwctjlWBbw== +react-google-charts@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/react-google-charts/-/react-google-charts-4.0.0.tgz#f648e4fe8ac8a1f47542c2cac040df6afb21e2d6" + integrity sha512-9OG0EkBb9JerKEPQYdhmAXnhGLzOdOHOPS9j7l+P1a3z1kcmq9mGDa7PUoX/VQUY4IjZl2/81nsO4o+1cuYsuw== + react-iframe@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/react-iframe/-/react-iframe-1.8.0.tgz#8c78f2c59b894ca5605fa7e45e61e27e57e96091"