From 460a17c7e73578b8135bd3b0fb2f6c3a5451542d Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Thu, 29 Dec 2022 13:15:27 +0300 Subject: [PATCH 01/12] remove unused import --- src/pages/GlobalPage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/GlobalPage.js b/src/pages/GlobalPage.js index a58e9e5..dd6b674 100644 --- a/src/pages/GlobalPage.js +++ b/src/pages/GlobalPage.js @@ -19,7 +19,6 @@ 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' From 01b64b2227b04d19e9c15bb82b25f5770c1add45 Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Thu, 5 Jan 2023 14:25:38 +0300 Subject: [PATCH 02/12] - rewrite TradingView chart comonent - add voltbar subgraph and queries - get and cache voltbar data - add more charts --- .gitignore | 2 + package.json | 5 +- src/apollo/client.js | 16 + src/apollo/queries.js | 12 +- src/components/GlobalChart/index.js | 165 +++++++---- src/components/TradingviewChart/area.js | 277 ++++++++++++++++++ .../TradingviewChart/{index.js => bars.js} | 53 ++-- src/contexts/GlobalData.js | 71 ++++- src/pages/GlobalPage.js | 121 ++++++-- src/utils/index.js | 22 ++ yarn.lock | 5 + 11 files changed, 618 insertions(+), 131 deletions(-) create mode 100644 src/components/TradingviewChart/area.js rename src/components/TradingviewChart/{index.js => bars.js} (87%) 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/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..d0ff518 100644 --- a/src/apollo/client.js +++ b/src/apollo/client.js @@ -10,6 +10,14 @@ export const client = new ApolloClient({ shouldBatch: true, }) +export const exchangeClient = 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,6 +42,14 @@ 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', diff --git a/src/apollo/queries.js b/src/apollo/queries.js index 6375ec6..ba90c9c 100644 --- a/src/apollo/queries.js +++ b/src/apollo/queries.js @@ -65,7 +65,7 @@ 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 - } }) { + } }) { number }` }) @@ -532,6 +532,16 @@ export const ALL_TOKENS = gql` } ` +export const ALL_RATIOS = gql` + query histories { + histories(first: 1000, orderBy: id, orderDirection: desc) { + id + date + ratio + } + } +` + export const TOKEN_SEARCH = gql` query tokens($value: String, $id: String) { asSymbol: tokens(where: { symbol_contains: $value }, orderBy: totalLiquidity, orderDirection: desc) { diff --git a/src/components/GlobalChart/index.js b/src/components/GlobalChart/index.js index 6fa0dc2..0296907 100644 --- a/src/components/GlobalChart/index.js +++ b/src/components/GlobalChart/index.js @@ -1,42 +1,49 @@ import React, { useState, useMemo, useEffect, useRef } from 'react' import { ResponsiveContainer } from 'recharts' import { timeframeOptions } from '../../constants' -import { useGlobalChartData, useGlobalData } from '../../contexts/GlobalData' +import { useBarAllRatios, 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' -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) // time window and window size for chart const timeWindow = timeframeOptions.ALL_TIME - const [volumeWindow, setVolumeWindow] = useState(VOLUME_WINDOW.DAYS) + // const [volumeWindow, setVolumeWindow] = useState(VOLUME_WINDOW.DAYS) // global historical data - const [dailyData, weeklyData] = useGlobalChartData() - const { totalLiquidityUSD, oneDayVolumeUSD, volumeChangeUSD, liquidityChangeUSD, oneWeekVolume, weeklyVolumeChange } = - useGlobalData() + const [dexDailyData] = useGlobalChartData() + const { totalLiquidityUSD, volumeChangeUSD, liquidityChangeUSD } = useGlobalData() + const allRatios = useBarAllRatios() + + const barChange = useMemo(() => { + if (!allRatios || !allRatios.length > 6) return + return (parseFloat(allRatios[0].ratio) - parseFloat(allRatios[6].ratio)) * 100 + }, [allRatios]) + console.log({ allRatios, dexDailyData, totalLiquidityUSD, barChange }) // based on window, get starttim let utcStartTime = getTimeframe(timeWindow) const chartDataFiltered = useMemo(() => { - let currentData = volumeWindow === VOLUME_WINDOW.DAYS ? dailyData : weeklyData + let currentData = dexDailyData return ( currentData && Object.keys(currentData) @@ -52,7 +59,7 @@ const GlobalChart = ({ display }) => { return !!item }) ) - }, [dailyData, utcStartTime, volumeWindow, weeklyData]) + }, [dexDailyData, utcStartTime]) const below800 = useMedia('(max-width: 800px)') // update the width on a window resize @@ -75,62 +82,106 @@ const GlobalChart = ({ display }) => { {below800 && ( )} - {chartDataFiltered && chartView === CHART_VIEW.LIQUIDITY && ( - )} {chartDataFiltered && chartView === CHART_VIEW.VOLUME && ( - )} - {display === 'volume' && ( - - setVolumeWindow(VOLUME_WINDOW.DAYS)} - > - D - - setVolumeWindow(VOLUME_WINDOW.WEEKLY)} - > - W - - + {allRatios && chartView === CHART_VIEW.BAR && ( + + formattedNum(num)} + /> + + )} + {chartDataFiltered && chartView === CHART_VIEW.REVENUE && ( + + formattedNum(num * 0.003, true)} + /> + )} ) : ( '' ) } - -export default GlobalChart diff --git a/src/components/TradingviewChart/area.js b/src/components/TradingviewChart/area.js new file mode 100644 index 0000000..595b0a5 --- /dev/null +++ b/src/components/TradingviewChart/area.js @@ -0,0 +1,277 @@ +import React, { useState, useEffect, useRef } from 'react' +import { createChart } from 'lightweight-charts' +import dayjs from 'dayjs' +import utc from 'dayjs/plugin/utc' +import { formattedNum, formattedPercent, rawPercent } 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 { set } from 'react-ga' + +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, +}) => { + // 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) + + // // parese the data and format for tardingview consumption + // let formattedData = datas[0]?.map( + // (sum = 0, entry => { + // sum += parseFloat(entry[fields[0]]) + // return { + // time: dayjs.unix(entry.date).utc().format('YYYY-MM-DD'), + // value: accumulate ? sum : parseFloat(entry[fields[0]]), + // } + // }) + // ) + + const formattedDatas = datas.map((data, i) => { + let sm = 0 + return data?.map((entry) => { + sm += parseFloat(entry[fields[i]]) + return { + time: dayjs.unix(entry.date).utc().format('YYYY-MM-DD'), + value: accumulate ? sm / (i + 1) : parseFloat(entry[fields[i]]) / (i + 1), + } + }) + }) + // const accumulatedDatas = datas.map((data, i) => { + // let sum = 0 + // return data?.map( + // ((sum = 0), + // (entry) => { + // sum += parseFloat(entry[fields[i]]) + // return { + // time: dayjs.unix(entry.date).utc().format('YYYY-MM-DD'), + // value: sum / (i + 1), + // } + // }) + // ) + // }) + + // 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 && formattedDatas[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 series = chart.addAreaSeries({ + // // topColor: '#5ED73E', + // // bottomColor: 'rgba(171, 219, 173, 0)', + // // lineColor: '#5ED73E', + // // lineWidth: 3, + // }) + // var series2 = chart.addAreaSeries({ + // // topColor: '#54c4b5', + // // bottomColor: 'rgba(181, 230, 223, 0)', + // // lineColor: '#54c4b5', + // // lineWidth: 3, + // }) + var seriesArr = configs.map((config) => { + return chart.addAreaSeries(config) + }) + + seriesArr.map((ser, i) => { + ser.setData(formattedDatas[i]) + }) + + // series.setData(formattedData) + // series2.setData(formattedDataV2) + 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 ?? formattedDatas[0][formattedDatas[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 price = param.seriesPrices.get(seriesArr[0]) + toolTip.innerHTML = + `
${title}
` + + `
` + + formatter(price, true) + + '
' + + '
' + + dateStr + + '
' + } + }) + + chart.timeScale().fitContent() + + setChartCreated(chart) + } + }, [ + base, + baseChange, + chartCreated, + configs, + darkMode, + datas, + formattedDatas, + 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/contexts/GlobalData.js b/src/contexts/GlobalData.js index 7035e5b..1e0aaa3 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 } from '../apollo/client' import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' import { useTimeframe } from './Application' @@ -18,6 +18,7 @@ import { ALL_PAIRS, ALL_TOKENS, TOP_LPS_PER_PAIRS, + ALL_RATIOS, } from '../apollo/queries' import weekOfYear from 'dayjs/plugin/weekOfYear' import { useAllPairData } from './PairData' @@ -28,6 +29,7 @@ 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' // format dayjs with the libraries that we need @@ -91,6 +93,14 @@ function reducer(state, { type, payload }) { } } + case UPDATE_ALL_RATIOS: { + const { allRatios } = payload + return { + ...state, + allRatios, + } + } + case UPDATE_TOP_LPS: { const { topLps } = payload return { @@ -171,6 +181,15 @@ export default function Provider({ children }) { }, }) }, []) + + const updateAllBarRatios = useCallback((allRatios) => { + dispatch({ + type: UPDATE_ALL_RATIOS, + payload: { + allRatios, + }, + }) + }, []) return ( !!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 +733,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/pages/GlobalPage.js b/src/pages/GlobalPage.js index dd6b674..e165910 100644 --- a/src/pages/GlobalPage.js +++ b/src/pages/GlobalPage.js @@ -2,37 +2,33 @@ import React, { useEffect } 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 { useAllPairsInUniswap, useGlobalData, useTopLps } 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 { CustomLink } from '../components/Link' import { PageWrapper, ContentWrapper } from '../components' +import { useAllPairData } from '../contexts/PairData' -const ListOptions = styled(AutoRow)` - height: 40px; - width: 100%; - font-size: 1.25rem; - font-weight: 600; +// const ListOptions = styled(AutoRow)` +// height: 40px; +// width: 100%; +// font-size: 1.25rem; +// font-weight: 600; - @media screen and (max-width: 640px) { - font-size: 1rem; - } -` +// @media screen and (max-width: 640px) { +// font-size: 1rem; +// } +// ` const GridRow = styled.div` display: grid; @@ -45,10 +41,45 @@ const GridRow = styled.div` function GlobalPage() { // get data for lists and totals - const allPairs = useAllPairData() - const allTokens = useAllTokenData() - const transactions = useGlobalTransactions() + // const allPairs = useAllPairData() + // const allTokens = useAllTokenData() + // const transactions = useGlobalTransactions() const { totalLiquidityUSD, oneDayVolumeUSD, volumeChangeUSD, liquidityChangeUSD } = useGlobalData() + const allPairs = useAllPairData() + // const topLps = useTopLps('volumeUSD') + // console.log({ allPairs }) + + const data = [ + ['Product', 'TVL in $USD'], + ['DEX', 1140000], + ['Stableswap', 250000], + ['FUSD V2', 70000], + ['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]) || []), + ] + // console.log({ pairsData }) + + 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', + } // breakpoints const below800 = useMedia('(max-width: 800px)') @@ -109,21 +140,59 @@ function GlobalPage() { {!below800 && ( - + - + )} {below800 && ( - + )} - + + + + + + + + + + + + + + + + + + + + + + + + + {/* Top Tokens See All @@ -149,7 +218,7 @@ function GlobalPage() { - + */}
diff --git a/src/utils/index.js b/src/utils/index.js index 061efef..3adaf2f 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -37,6 +37,28 @@ 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" From e969f70dbd5f52b4a23e50417b055004f4fb1f5c Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Fri, 6 Jan 2023 15:59:50 +0300 Subject: [PATCH 03/12] fetch stableswap data, add stableswap liquidity to liquidity chart --- .vscode/settings.json | 3 - src/apollo/client.js | 9 +- src/apollo/queries.js | 48 +++++- src/components/GlobalChart/index.js | 22 ++- src/components/TradingviewChart/area.js | 10 +- src/contexts/GlobalData.js | 213 ++++++++++++++++++++++-- src/pages/GlobalPage.js | 17 +- 7 files changed, 287 insertions(+), 35 deletions(-) delete mode 100644 .vscode/settings.json 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/src/apollo/client.js b/src/apollo/client.js index d0ff518..3aaac96 100644 --- a/src/apollo/client.js +++ b/src/apollo/client.js @@ -10,7 +10,7 @@ export const client = new ApolloClient({ shouldBatch: true, }) -export const exchangeClient = new ApolloClient({ +export const v2Client = new ApolloClient({ link: new HttpLink({ uri: 'https://api.thegraph.com/subgraphs/name/voltfinance/voltage-exchange-v2', }), @@ -56,3 +56,10 @@ export const blockClient = new ApolloClient({ }), cache: new InMemoryCache(), }) + +export const stableswapClient = new ApolloClient({ + link: new HttpLink({ + uri: 'https://api.thegraph.com/subgraphs/name/t0mcr8se/stableswap-subgraph', + }), + cache: new InMemoryCache(), +}) diff --git a/src/apollo/queries.js b/src/apollo/queries.js index ba90c9c..0d56184 100644 --- a/src/apollo/queries.js +++ b/src/apollo/queries.js @@ -64,7 +64,8 @@ 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) { @@ -542,6 +558,36 @@ export const ALL_RATIOS = gql` } ` +export const STABLESWAP_DATA = gql` + { + systemInfos(first: 5) { + id + exchangeCount + swapCount + tokenCount + } + swaps(first: 5) { + id + address + numTokens + lpTokenSupply + virtualPrice + 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) { diff --git a/src/components/GlobalChart/index.js b/src/components/GlobalChart/index.js index 0296907..70a00c2 100644 --- a/src/components/GlobalChart/index.js +++ b/src/components/GlobalChart/index.js @@ -1,7 +1,7 @@ import React, { useState, useMemo, useEffect, useRef } from 'react' import { ResponsiveContainer } from 'recharts' import { timeframeOptions } from '../../constants' -import { useBarAllRatios, useGlobalChartData, useGlobalData } from '../../contexts/GlobalData' +import { useBarAllRatios, useGlobalChartData, useGlobalData, useStableswapData } from '../../contexts/GlobalData' import { useMedia } from 'react-use' import DropdownSelect from '../DropdownSelect' import TradingViewChartArea from '../TradingviewChart/area' @@ -30,14 +30,15 @@ export default function GlobalChart({ view }) { // global historical data const [dexDailyData] = useGlobalChartData() - const { totalLiquidityUSD, volumeChangeUSD, liquidityChangeUSD } = useGlobalData() + const { volumeChangeUSD, liquidityChangeUSD, totalProtocolLiquidityUSD } = useGlobalData() const allRatios = useBarAllRatios() + const stableswapData = useStableswapData() const barChange = useMemo(() => { if (!allRatios || !allRatios.length > 6) return return (parseFloat(allRatios[0].ratio) - parseFloat(allRatios[6].ratio)) * 100 }, [allRatios]) - console.log({ allRatios, dexDailyData, totalLiquidityUSD, barChange }) + console.log({ stableswapData }) // based on window, get starttim let utcStartTime = getTimeframe(timeWindow) @@ -82,11 +83,11 @@ export default function GlobalChart({ view }) { {below800 && ( )} - {chartDataFiltered && chartView === CHART_VIEW.LIQUIDITY && ( + {chartDataFiltered && stableswapData && chartView === CHART_VIEW.LIQUIDITY && ( )} diff --git a/src/components/TradingviewChart/area.js b/src/components/TradingviewChart/area.js index 595b0a5..c8f8008 100644 --- a/src/components/TradingviewChart/area.js +++ b/src/components/TradingviewChart/area.js @@ -40,6 +40,7 @@ const TradingViewChartArea = ({ accumulate = false, configs, formatter = formattedNum, + sumUp = true, }) => { // reference for DOM element to create with chart const type = CHART_TYPES.AREA @@ -65,7 +66,7 @@ const TradingViewChartArea = ({ sm += parseFloat(entry[fields[i]]) return { time: dayjs.unix(entry.date).utc().format('YYYY-MM-DD'), - value: accumulate ? sm / (i + 1) : parseFloat(entry[fields[i]]) / (i + 1), + value: accumulate ? sm : parseFloat(entry[fields[i]]), } }) }) @@ -219,11 +220,14 @@ const TradingViewChartArea = ({ .endOf('week') .format('MMMM D, YYYY') : dayjs(param.time.year + '-' + param.time.month + '-' + param.time.day).format('MMMM D, YYYY') - var price = param.seriesPrices.get(seriesArr[0]) + var prices = seriesArr.map((ser) => param.seriesPrices.get(ser) ?? 0) + console.log(param.seriesPrices) + var totalPrice = prices.reduce((sum, price) => sum + price, 0) + console.log({ totalPrice }) toolTip.innerHTML = `
${title}
` + `
` + - formatter(price, true) + + formatter(totalPrice, true) + '
' + '
' + dateStr + diff --git a/src/contexts/GlobalData.js b/src/contexts/GlobalData.js index 1e0aaa3..ce6c6ad 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 { barClient, client } from '../apollo/client' +import { barClient, client, stableswapClient } from '../apollo/client' import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' import { useTimeframe } from './Application' @@ -19,9 +19,11 @@ import { ALL_TOKENS, TOP_LPS_PER_PAIRS, ALL_RATIOS, + STABLESWAP_DATA, } from '../apollo/queries' import weekOfYear from 'dayjs/plugin/weekOfYear' import { useAllPairData } from './PairData' +import { formatEther } from 'ethers/utils' const UPDATE = 'UPDATE' const UPDATE_TXNS = 'UPDATE_TXNS' const UPDATE_CHART = 'UPDATE_CHART' @@ -31,6 +33,7 @@ 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' // format dayjs with the libraries that we need dayjs.extend(utc) @@ -108,6 +111,15 @@ function reducer(state, { type, payload }) { topLps, } } + + case UPDATE_STABLESWAP_DATA: { + const { stableswapData } = payload + return { + ...state, + stableswapData, + } + } + default: { throw Error(`Unexpected action type in DataContext reducer: '${type}'.`) } @@ -190,6 +202,16 @@ export default function Provider({ children }) { }, }) }, []) + + const updateStableSwapData = useCallback((stableswapData) => { + dispatch({ + type: UPDATE_STABLESWAP_DATA, + payload: { + stableswapData, + }, + }) + }, []) + return ( @@ -224,6 +248,132 @@ export default function Provider({ children }) { ) } +/** + * 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 + */ +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 + return { + ...stableswapData, + histories: { + [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(), + }, + } +} + /** * Gets all the global data for the overview page. * Needs current eth price and the old eth price to get @@ -253,6 +403,8 @@ async function getGlobalData(ethPrice, oldEthPrice) { utcTwoWeeksBack, ]) + let stableswapData = await fetchFormatStableswapData() + // fetch the global data let result = await client.query({ query: GLOBAL_DATA(), @@ -319,6 +471,10 @@ async function getGlobalData(ethPrice, oldEthPrice) { data.liquidityChangeUSD = liquidityChangeUSD data.oneDayTxns = oneDayTxns data.txnChange = txnChange + data.totalProtocolLiquidityUSD = + parseFloat(data.totalLiquidityUSD) + + parseFloat(formatEther(stableswapData.swaps[1].lpTokenSupply)) + + parseFloat(formatEther(stableswapData.swaps[0].lpTokenSupply)) } } catch (e) { console.log(e) @@ -558,13 +714,26 @@ async function getAllBarRatios() { } } +async function getStableswapData() { + try { + let result = await stableswapClient.query({ + query: STABLESWAP_DATA, + fetchPolicy: 'cache-first', + }) + console.log({ result }) + 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, updateAllBarRatios }, + { update, updateAllPairsInUniswap, updateAllTokensInUniswap, updateStableSwapData }, ] = useGlobalDataContext() const [ethPrice, oldEthPrice] = useEthPrice() @@ -575,26 +744,46 @@ export function useGlobalData() { let globalData = await getGlobalData(ethPrice, oldEthPrice) globalData && update(globalData) - let allPairs = await getAllPairsOnUniswap() - updateAllPairsInUniswap(allPairs) - - let allTokens = await getAllTokensOnUniswap() - updateAllTokensInUniswap(allTokens) + // let allPairs = await getAllPairsOnUniswap() + // updateAllPairsInUniswap(allPairs) - let allBarRatios = await getAllBarRatios() - updateAllBarRatios(allBarRatios) + // let allTokens = await getAllTokensOnUniswap() + // updateAllTokensInUniswap(allTokens) } if (!data && ethPrice && oldEthPrice) { fetchData() } - }, [ethPrice, oldEthPrice, update, data, updateAllPairsInUniswap, updateAllTokensInUniswap, updateAllBarRatios]) + }, [ethPrice, oldEthPrice, update, data, updateAllPairsInUniswap, updateAllTokensInUniswap, updateStableSwapData]) return data || {} } export function useBarAllRatios() { - const [state] = useGlobalDataContext() - return state?.allRatios + const [state, { updateAllBarRatios }] = useGlobalDataContext() + const allRatios = state?.allRatios + useEffect(() => { + if (allRatios) return + async function fetchData() { + let allBarRatios = await getAllBarRatios() + updateAllBarRatios(allBarRatios) + } + fetchData() + }, [allRatios, updateAllBarRatios]) + return allRatios +} + +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 stableswapData } export function useGlobalChartData() { diff --git a/src/pages/GlobalPage.js b/src/pages/GlobalPage.js index e165910..08dceb3 100644 --- a/src/pages/GlobalPage.js +++ b/src/pages/GlobalPage.js @@ -40,14 +40,14 @@ const GridRow = styled.div` ` function GlobalPage() { - // get data for lists and totals - // const allPairs = useAllPairData() - // const allTokens = useAllTokenData() - // const transactions = useGlobalTransactions() - const { totalLiquidityUSD, oneDayVolumeUSD, volumeChangeUSD, liquidityChangeUSD } = useGlobalData() + const { + totalLiquidityUSD, + oneDayVolumeUSD, + volumeChangeUSD, + liquidityChangeUSD, + totalProtocolLiquidityUSD, + } = useGlobalData() const allPairs = useAllPairData() - // const topLps = useTopLps('volumeUSD') - // console.log({ allPairs }) const data = [ ['Product', 'TVL in $USD'], @@ -64,7 +64,8 @@ function GlobalPage() { .map((pair) => [`${pair.token0.symbol}/${pair.token1.symbol}`, parseFloat(pair.volumeUSD)]) || []), // ...(topLps?.slice(0, 5).map((lp) => [lp.pairName, lp.volumeUSD]) || []), ] - // console.log({ pairsData }) + + console.log(totalProtocolLiquidityUSD) const pairsOptions = { title: 'Top 10 Traded Pairs', From 49c0f0f9b44d1dd507f448fc5585a6127588488d Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Fri, 13 Jan 2023 15:44:50 +0300 Subject: [PATCH 04/12] add volt price --- src/components/GlobalStats/index.js | 7 ++++++- src/constants/index.js | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) 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/constants/index.js b/src/constants/index.js index c5b72a3..596db45 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -34,3 +34,5 @@ export const PAIR_BLACKLIST = ['0xb6a741f37d6e455ebcc9f17e2c16d0586c3f57a5'] * For tokens that cause erros on fee calculations */ export const FEE_WARNING_TOKENS = ['0xd46ba6d942050d489dbd938a2c909a5d5039a161'] + +export const VOLT_ADDRESS = '0x34ef2cc892a88415e9f02b91bfa9c91fc0be6bd4' From 56676f6c174286a991faf69d36304a086d573f10 Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Fri, 13 Jan 2023 15:46:01 +0300 Subject: [PATCH 05/12] add fusd data --- src/apollo/client.js | 7 +++ src/apollo/queries.js | 27 +++++++++ src/contexts/GlobalData.js | 119 +++++++++++++++++++++++++++++++------ 3 files changed, 134 insertions(+), 19 deletions(-) diff --git a/src/apollo/client.js b/src/apollo/client.js index 3aaac96..907ef7e 100644 --- a/src/apollo/client.js +++ b/src/apollo/client.js @@ -63,3 +63,10 @@ export const stableswapClient = new ApolloClient({ }), 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 0d56184..df579b4 100644 --- a/src/apollo/queries.js +++ b/src/apollo/queries.js @@ -915,3 +915,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/contexts/GlobalData.js b/src/contexts/GlobalData.js index ce6c6ad..8c9651c 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 { barClient, client, stableswapClient } 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' @@ -20,6 +20,7 @@ import { TOP_LPS_PER_PAIRS, ALL_RATIOS, STABLESWAP_DATA, + FUSD_DATA, } from '../apollo/queries' import weekOfYear from 'dayjs/plugin/weekOfYear' import { useAllPairData } from './PairData' @@ -34,6 +35,7 @@ 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) @@ -120,6 +122,14 @@ function reducer(state, { type, payload }) { } } + case UPDATE_FUSD_DATA: { + const { fusdData } = payload + return { + ...state, + fusdData, + } + } + default: { throw Error(`Unexpected action type in DataContext reducer: '${type}'.`) } @@ -212,6 +222,15 @@ export default function Provider({ children }) { }) }, []) + const updateFusdData = useCallback((fusdData) => { + dispatch({ + type: UPDATE_FUSD_DATA, + payload: { + fusdData, + }, + }) + }, []) + return ( @@ -248,6 +269,18 @@ 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 @@ -255,6 +288,7 @@ export default function Provider({ children }) { * @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 = {} @@ -355,22 +389,24 @@ async function getGlobalDataV2(ethPrice, oldEthPrice) { 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: { - [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(), - }, + histories: stableswapHistory, } } @@ -404,6 +440,7 @@ async function getGlobalData(ethPrice, oldEthPrice) { ]) let stableswapData = await fetchFormatStableswapData() + let fusdData = await getFusdData() // fetch the global data let result = await client.query({ @@ -471,10 +508,33 @@ async function getGlobalData(ethPrice, oldEthPrice) { data.liquidityChangeUSD = liquidityChangeUSD data.oneDayTxns = oneDayTxns data.txnChange = txnChange - data.totalProtocolLiquidityUSD = - parseFloat(data.totalLiquidityUSD) + + data.stableswapLiquidityUSD = parseFloat(formatEther(stableswapData.swaps[1].lpTokenSupply)) + parseFloat(formatEther(stableswapData.swaps[0].lpTokenSupply)) + data.fusdLiquidityUSD = parseFloat(fusdData?.massets?.[0]?.totalSupply?.simple) + data.totalProtocolLiquidityUSD = + parseFloat(data.totalLiquidityUSD) + data.stableswapLiquidityUSD + data.fusdLiquidityUSD + 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(), + } + console.log(data.fusdData) + data.stableswapData = stableswapData } } catch (e) { console.log(e) @@ -720,7 +780,6 @@ async function getStableswapData() { query: STABLESWAP_DATA, fetchPolicy: 'cache-first', }) - console.log({ result }) return result?.data } catch (e) { console.log(e) @@ -772,6 +831,20 @@ export function useBarAllRatios() { 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 @@ -783,7 +856,15 @@ export function useStableswapData() { } fetchData() }, [stableswapData, updateStableSwapData]) - return stableswapData + return useMemo(() => { + if (!stableswapData) return + + // sum up liquidity and volume of both stableswapData.histories + + return { ...stableswapData } + + return stableswapData + }, [stableswapData]) } export function useGlobalChartData() { From 309c083a8a6ad8a47eaf3a15c9aee24dc7b1bd26 Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Fri, 13 Jan 2023 15:46:20 +0300 Subject: [PATCH 06/12] show fusd data, limit timeframe to 6 months --- src/components/GlobalChart/index.js | 63 ++++++++----------------- src/components/TradingviewChart/area.js | 36 ++++++-------- src/constants/index.js | 1 + src/pages/GlobalPage.js | 16 ++++--- src/utils/index.js | 5 +- 5 files changed, 49 insertions(+), 72 deletions(-) diff --git a/src/components/GlobalChart/index.js b/src/components/GlobalChart/index.js index 70a00c2..3ce8f14 100644 --- a/src/components/GlobalChart/index.js +++ b/src/components/GlobalChart/index.js @@ -1,7 +1,7 @@ import React, { useState, useMemo, useEffect, useRef } from 'react' import { ResponsiveContainer } from 'recharts' import { timeframeOptions } from '../../constants' -import { useBarAllRatios, useGlobalChartData, useGlobalData, useStableswapData } from '../../contexts/GlobalData' +import { useBarAllRatios, useGlobalChartData, useGlobalData } from '../../contexts/GlobalData' import { useMedia } from 'react-use' import DropdownSelect from '../DropdownSelect' import TradingViewChartArea from '../TradingviewChart/area' @@ -24,43 +24,20 @@ export default function GlobalChart({ view }) { // chart options const [chartView, setChartView] = useState(view) - // time window and window size for chart - const timeWindow = timeframeOptions.ALL_TIME - // const [volumeWindow, setVolumeWindow] = useState(VOLUME_WINDOW.DAYS) + const timeWindow = timeframeOptions.SIX_MONTHS - // global historical data const [dexDailyData] = useGlobalChartData() - const { volumeChangeUSD, liquidityChangeUSD, totalProtocolLiquidityUSD } = useGlobalData() + const { volumeChangeUSD, liquidityChangeUSD, totalProtocolLiquidityUSD, stableswapData, fusdData } = useGlobalData() const allRatios = useBarAllRatios() - const stableswapData = useStableswapData() const barChange = useMemo(() => { if (!allRatios || !allRatios.length > 6) return return (parseFloat(allRatios[0].ratio) - parseFloat(allRatios[6].ratio)) * 100 }, [allRatios]) - console.log({ stableswapData }) // based on window, get starttim let utcStartTime = getTimeframe(timeWindow) - const chartDataFiltered = useMemo(() => { - let currentData = dexDailyData - return ( - currentData && - Object.keys(currentData) - ?.map((key) => { - let item = currentData[key] - if (item.date > utcStartTime) { - return item - } else { - return - } - }) - .filter((item) => { - return !!item - }) - ) - }, [dexDailyData, utcStartTime]) const below800 = useMedia('(max-width: 800px)') // update the width on a window resize @@ -78,15 +55,15 @@ export default function GlobalChart({ view }) { 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 && stableswapData && chartView === CHART_VIEW.LIQUIDITY && ( + {dexDailyData && stableswapData && fusdData && chartView === CHART_VIEW.LIQUIDITY && ( )} - {chartDataFiltered && chartView === CHART_VIEW.VOLUME && ( + {dexDailyData && chartView === CHART_VIEW.VOLUME && ( )} @@ -163,13 +136,14 @@ export default function GlobalChart({ view }) { useWeekly={false} accumulate={false} formatter={(num, _) => formattedNum(num)} + startTime={utcStartTime} /> )} - {chartDataFiltered && chartView === CHART_VIEW.REVENUE && ( + {dexDailyData && chartView === CHART_VIEW.REVENUE && ( formattedNum(num * 0.003, true)} + startTime={utcStartTime} /> )} diff --git a/src/components/TradingviewChart/area.js b/src/components/TradingviewChart/area.js index c8f8008..3f1678d 100644 --- a/src/components/TradingviewChart/area.js +++ b/src/components/TradingviewChart/area.js @@ -2,13 +2,14 @@ import React, { useState, useEffect, useRef } from 'react' import { createChart } from 'lightweight-charts' import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' -import { formattedNum, formattedPercent, rawPercent } from '../../utils' +import { formattedNum, formattedPercent, getTimeframe, rawPercent } 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 { set } from 'react-ga' +import { timeframeOptions } from '../../constants' const CHART_TYPES = { BAR: 'BAR', @@ -41,6 +42,7 @@ const TradingViewChartArea = ({ configs, formatter = formattedNum, sumUp = true, + startTime = getTimeframe(timeframeOptions.ALL_TIME), }) => { // reference for DOM element to create with chart const type = CHART_TYPES.AREA @@ -59,30 +61,22 @@ const TradingViewChartArea = ({ // } // }) // ) + console.log({ datas }) const formattedDatas = datas.map((data, i) => { let sm = 0 - return data?.map((entry) => { - sm += parseFloat(entry[fields[i]]) - return { - time: dayjs.unix(entry.date).utc().format('YYYY-MM-DD'), - value: accumulate ? sm : parseFloat(entry[fields[i]]), - } - }) + return data + ?.map((entry) => { + sm += parseFloat(entry[fields[i]]) + return { + time: dayjs.unix(entry.date).utc().format('YYYY-MM-DD'), + value: accumulate ? sm : parseFloat(entry[fields[i]]), + timestamp: entry.date, + } + }) + ?.filter((entry) => entry.timestamp >= startTime) }) - // const accumulatedDatas = datas.map((data, i) => { - // let sum = 0 - // return data?.map( - // ((sum = 0), - // (entry) => { - // sum += parseFloat(entry[fields[i]]) - // return { - // time: dayjs.unix(entry.date).utc().format('YYYY-MM-DD'), - // value: sum / (i + 1), - // } - // }) - // ) - // }) + console.log(formattedDatas) // adjust the scale based on the type of chart const topScale = 0.32 diff --git a/src/constants/index.js b/src/constants/index.js index 596db45..b0f171c 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', } diff --git a/src/pages/GlobalPage.js b/src/pages/GlobalPage.js index 08dceb3..3598d9a 100644 --- a/src/pages/GlobalPage.js +++ b/src/pages/GlobalPage.js @@ -40,20 +40,26 @@ const GridRow = styled.div` ` function GlobalPage() { + // Add a volt price next fuse + // Start liquidity from 6 months + // Single volume line for everything + const { totalLiquidityUSD, oneDayVolumeUSD, volumeChangeUSD, liquidityChangeUSD, - totalProtocolLiquidityUSD, + stableswapLiquidityUSD, + fusdLiquidityUSD, } = useGlobalData() + const voltagePrice = '0.00019' const allPairs = useAllPairData() const data = [ ['Product', 'TVL in $USD'], - ['DEX', 1140000], - ['Stableswap', 250000], - ['FUSD V2', 70000], + ['DEX', totalLiquidityUSD], + ['Stableswap', stableswapLiquidityUSD], + ['FUSD V2', fusdLiquidityUSD], ['xVOLT', 72000], ] const pairsData = [ @@ -65,8 +71,6 @@ function GlobalPage() { // ...(topLps?.slice(0, 5).map((lp) => [lp.pairName, lp.volumeUSD]) || []), ] - console.log(totalProtocolLiquidityUSD) - const pairsOptions = { title: 'Top 10 Traded Pairs', pieHole: 0.4, diff --git a/src/utils/index.js b/src/utils/index.js index 3adaf2f..4e136bc 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -18,6 +18,7 @@ dayjs.extend(utc) export function getTimeframe(timeWindow) { const utcEndTime = dayjs.utc() + console.log(timeWindow, timeframeOptions.SIX_MONTHS, timeframeOptions.SIX_MONTHS === timeWindow) // based on window, get starttime let utcStartTime switch (timeWindow) { @@ -30,6 +31,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 @@ -58,7 +62,6 @@ export function getTimeframeDay(days) { // return utcStartTime } - export function getPoolLink(token0Address, token1Address = null, remove = false) { if (!token1Address) { return ( From 82b98eeebe0ffdc42d8f1157a3a45542d8adac8e Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Fri, 13 Jan 2023 15:50:43 +0300 Subject: [PATCH 07/12] remove redundant/commented code --- src/components/TradingviewChart/area.js | 30 +------------------------ 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/src/components/TradingviewChart/area.js b/src/components/TradingviewChart/area.js index 3f1678d..5723b8c 100644 --- a/src/components/TradingviewChart/area.js +++ b/src/components/TradingviewChart/area.js @@ -2,13 +2,12 @@ import React, { useState, useEffect, useRef } from 'react' import { createChart } from 'lightweight-charts' import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' -import { formattedNum, formattedPercent, getTimeframe, rawPercent } from '../../utils' +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 { set } from 'react-ga' import { timeframeOptions } from '../../constants' const CHART_TYPES = { @@ -51,18 +50,6 @@ const TradingViewChartArea = ({ // pointer to the chart object const [chartCreated, setChartCreated] = useState(false) - // // parese the data and format for tardingview consumption - // let formattedData = datas[0]?.map( - // (sum = 0, entry => { - // sum += parseFloat(entry[fields[0]]) - // return { - // time: dayjs.unix(entry.date).utc().format('YYYY-MM-DD'), - // value: accumulate ? sum : parseFloat(entry[fields[0]]), - // } - // }) - // ) - console.log({ datas }) - const formattedDatas = datas.map((data, i) => { let sm = 0 return data @@ -76,7 +63,6 @@ const TradingViewChartArea = ({ }) ?.filter((entry) => entry.timestamp >= startTime) }) - console.log(formattedDatas) // adjust the scale based on the type of chart const topScale = 0.32 @@ -145,18 +131,6 @@ const TradingViewChartArea = ({ }, }) - // var series = chart.addAreaSeries({ - // // topColor: '#5ED73E', - // // bottomColor: 'rgba(171, 219, 173, 0)', - // // lineColor: '#5ED73E', - // // lineWidth: 3, - // }) - // var series2 = chart.addAreaSeries({ - // // topColor: '#54c4b5', - // // bottomColor: 'rgba(181, 230, 223, 0)', - // // lineColor: '#54c4b5', - // // lineWidth: 3, - // }) var seriesArr = configs.map((config) => { return chart.addAreaSeries(config) }) @@ -165,8 +139,6 @@ const TradingViewChartArea = ({ ser.setData(formattedDatas[i]) }) - // series.setData(formattedData) - // series2.setData(formattedDataV2) var toolTip = document.createElement('div') toolTip.setAttribute('id', 'tooltip-id' + type) toolTip.className = darkMode ? 'three-line-legend-dark' : 'three-line-legend' From 3139644d7f151edefdb6ac07b52923d24e166a32 Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Fri, 13 Jan 2023 17:14:10 +0300 Subject: [PATCH 08/12] add xvolt to tvl --- src/apollo/queries.js | 16 +++++- src/components/GlobalChart/index.js | 37 +++++++++++--- src/components/TradingviewChart/area.js | 2 - src/contexts/GlobalData.js | 65 ++++++++++++++++++------- src/contexts/TokenData.js | 2 +- src/utils/index.js | 1 - 6 files changed, 91 insertions(+), 32 deletions(-) diff --git a/src/apollo/queries.js b/src/apollo/queries.js index df579b4..c414368 100644 --- a/src/apollo/queries.js +++ b/src/apollo/queries.js @@ -548,13 +548,24 @@ export const ALL_TOKENS = gql` } ` -export const ALL_RATIOS = gql` - query histories { +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 + } } ` @@ -572,6 +583,7 @@ export const STABLESWAP_DATA = gql` numTokens lpTokenSupply virtualPrice + cumulativeVolume tokens { id } diff --git a/src/components/GlobalChart/index.js b/src/components/GlobalChart/index.js index 3ce8f14..07c1d99 100644 --- a/src/components/GlobalChart/index.js +++ b/src/components/GlobalChart/index.js @@ -1,7 +1,7 @@ import React, { useState, useMemo, useEffect, useRef } from 'react' import { ResponsiveContainer } from 'recharts' import { timeframeOptions } from '../../constants' -import { useBarAllRatios, useGlobalChartData, useGlobalData } from '../../contexts/GlobalData' +import { useGlobalChartData, useGlobalData } from '../../contexts/GlobalData' import { useMedia } from 'react-use' import DropdownSelect from '../DropdownSelect' import TradingViewChartArea from '../TradingviewChart/area' @@ -27,8 +27,17 @@ export default function GlobalChart({ view }) { const timeWindow = timeframeOptions.SIX_MONTHS const [dexDailyData] = useGlobalChartData() - const { volumeChangeUSD, liquidityChangeUSD, totalProtocolLiquidityUSD, stableswapData, fusdData } = useGlobalData() - const allRatios = useBarAllRatios() + const { + volumeChangeUSD, + liquidityChangeUSD, + totalProtocolLiquidityUSD, + stableswapData, + fusdData, + totalVolumeUSD, + xvoltData, + } = useGlobalData() + const allRatios = xvoltData?.histories + console.log(allRatios) const barChange = useMemo(() => { if (!allRatios || !allRatios.length > 6) return @@ -60,10 +69,15 @@ export default function GlobalChart({ view }) { {below800 && ( )} - {dexDailyData && stableswapData && fusdData && chartView === CHART_VIEW.LIQUIDITY && ( + {dexDailyData && stableswapData && fusdData && xvoltData && chartView === CHART_VIEW.LIQUIDITY && ( param.seriesPrices.get(ser) ?? 0) - console.log(param.seriesPrices) var totalPrice = prices.reduce((sum, price) => sum + price, 0) - console.log({ totalPrice }) toolTip.innerHTML = `
${title}
` + `
` + diff --git a/src/contexts/GlobalData.js b/src/contexts/GlobalData.js index 8c9651c..0da9dc1 100644 --- a/src/contexts/GlobalData.js +++ b/src/contexts/GlobalData.js @@ -18,13 +18,15 @@ import { ALL_PAIRS, ALL_TOKENS, TOP_LPS_PER_PAIRS, - ALL_RATIOS, 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' @@ -441,6 +443,8 @@ async function getGlobalData(ethPrice, oldEthPrice) { 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({ @@ -512,8 +516,34 @@ async function getGlobalData(ethPrice, oldEthPrice) { 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(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 @@ -533,7 +563,6 @@ async function getGlobalData(ethPrice, oldEthPrice) { }) .reverse(), } - console.log(data.fusdData) data.stableswapData = stableswapData } } catch (e) { @@ -765,10 +794,10 @@ async function getAllTokensOnUniswap() { async function getAllBarRatios() { try { let result = await barClient.query({ - query: ALL_RATIOS, + query: BAR_QUERY, fetchPolicy: 'cache-first', }) - return result?.data?.histories + return result?.data } catch (e) { console.log(e) } @@ -817,19 +846,19 @@ export function useGlobalData() { return data || {} } -export function useBarAllRatios() { - const [state, { updateAllBarRatios }] = useGlobalDataContext() - const allRatios = state?.allRatios - useEffect(() => { - if (allRatios) return - async function fetchData() { - let allBarRatios = await getAllBarRatios() - updateAllBarRatios(allBarRatios) - } - fetchData() - }, [allRatios, updateAllBarRatios]) - return allRatios -} +// 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() 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/utils/index.js b/src/utils/index.js index 4e136bc..ba3b927 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -18,7 +18,6 @@ dayjs.extend(utc) export function getTimeframe(timeWindow) { const utcEndTime = dayjs.utc() - console.log(timeWindow, timeframeOptions.SIX_MONTHS, timeframeOptions.SIX_MONTHS === timeWindow) // based on window, get starttime let utcStartTime switch (timeWindow) { From 6c32bf31fb8f97b08e34f954aa4190a68430aa87 Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Mon, 16 Jan 2023 12:47:37 +0300 Subject: [PATCH 09/12] fill empty gaps in data, sum multiple feeds together --- src/components/GlobalChart/index.js | 46 ++++++++++---------- src/components/TradingviewChart/area.js | 28 ++++--------- src/hooks/useFormattedDatas.ts | 56 +++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 42 deletions(-) create mode 100644 src/hooks/useFormattedDatas.ts diff --git a/src/components/GlobalChart/index.js b/src/components/GlobalChart/index.js index 07c1d99..6c03d55 100644 --- a/src/components/GlobalChart/index.js +++ b/src/components/GlobalChart/index.js @@ -6,6 +6,7 @@ import { useMedia } from 'react-use' import DropdownSelect from '../DropdownSelect' import TradingViewChartArea from '../TradingviewChart/area' import { formattedNum, getTimeframe } from '../../utils' +import { useFormattedDatas } from '../../hooks/useFormattedDatas' export const CHART_VIEW = { VOLUME: 'Volume', @@ -37,11 +38,18 @@ export default function GlobalChart({ view }) { xvoltData, } = useGlobalData() const allRatios = xvoltData?.histories - console.log(allRatios) + const stablesTvl = useFormattedDatas( + [fusdData.massetDayDatas, Object.values(stableswapData.histories)[0], Object.values(stableswapData.histories)[1]], + ['totalSupply', 'supplyFormatted', 'supplyFormatted'], + getTimeframe(timeWindow), + false, + true + ) + console.log(stablesTvl) const barChange = useMemo(() => { if (!allRatios || !allRatios.length > 6) return - return (parseFloat(allRatios[0].ratio) - parseFloat(allRatios[6].ratio)) * 100 + return (parseFloat(allRatios[allRatios.length - 1].ratio) - parseFloat(allRatios[allRatios.length - 7].ratio)) * 100 }, [allRatios]) // based on window, get starttim @@ -69,15 +77,10 @@ export default function GlobalChart({ view }) { {below800 && ( )} - {dexDailyData && stableswapData && fusdData && xvoltData && chartView === CHART_VIEW.LIQUIDITY && ( + {dexDailyData && stablesTvl && xvoltData && chartView === CHART_VIEW.LIQUIDITY && ( @@ -117,11 +113,16 @@ export default function GlobalChart({ view }) { {dexDailyData && chartView === CHART_VIEW.VOLUME && ( diff --git a/src/components/TradingviewChart/area.js b/src/components/TradingviewChart/area.js index 806e309..d4ff79d 100644 --- a/src/components/TradingviewChart/area.js +++ b/src/components/TradingviewChart/area.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef } from 'react' +import React, { useState, useEffect, useRef, useMemo } from 'react' import { createChart } from 'lightweight-charts' import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' @@ -9,6 +9,7 @@ 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', @@ -40,7 +41,7 @@ const TradingViewChartArea = ({ accumulate = false, configs, formatter = formattedNum, - sumUp = true, + sumUp = false, startTime = getTimeframe(timeframeOptions.ALL_TIME), }) => { // reference for DOM element to create with chart @@ -50,20 +51,7 @@ const TradingViewChartArea = ({ // pointer to the chart object const [chartCreated, setChartCreated] = useState(false) - const formattedDatas = datas.map((data, i) => { - let sm = 0 - return data - ?.map((entry) => { - sm += parseFloat(entry[fields[i]]) - return { - time: dayjs.unix(entry.date).utc().format('YYYY-MM-DD'), - value: accumulate ? sm : parseFloat(entry[fields[i]]), - timestamp: entry.date, - } - }) - ?.filter((entry) => entry.timestamp >= startTime) - }) - + const formattedSyncedSummedDatas = useFormattedDatas(datas, fields, startTime, accumulate, sumUp) // adjust the scale based on the type of chart const topScale = 0.32 @@ -85,7 +73,7 @@ const TradingViewChartArea = ({ // if no chart created yet, create one with options and add to DOM manually useEffect(() => { - if (!chartCreated && formattedDatas[0]?.length > 0) { + if (!chartCreated && formattedSyncedSummedDatas[0]?.length > 0) { var chart = createChart(ref.current, { width: width, height: HEIGHT, @@ -136,7 +124,7 @@ const TradingViewChartArea = ({ }) seriesArr.map((ser, i) => { - ser.setData(formattedDatas[i]) + ser.setData(formattedSyncedSummedDatas[i]) }) var toolTip = document.createElement('div') @@ -159,7 +147,7 @@ const TradingViewChartArea = ({ toolTip.innerHTML = `
${title}
` + `
` + - formatter(base ?? formattedDatas[0][formattedDatas[0].length - 1].value, true) + + formatter(base ?? formattedSyncedSummedDatas[0][formattedSyncedSummedDatas[0].length - 1].value, true) + `${formattedPercentChange}` + '
' } @@ -210,7 +198,7 @@ const TradingViewChartArea = ({ configs, darkMode, datas, - formattedDatas, + formattedSyncedSummedDatas, formatter, textColor, title, diff --git a/src/hooks/useFormattedDatas.ts b/src/hooks/useFormattedDatas.ts new file mode 100644 index 0000000..1d2acee --- /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 + }, [datas, formattedSyncedDatas, sumFields]) +} From f343a907532ce0bbfb534193f6abf30cce18a745 Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Mon, 16 Jan 2023 12:48:09 +0300 Subject: [PATCH 10/12] fix issue --- src/hooks/useFormattedDatas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useFormattedDatas.ts b/src/hooks/useFormattedDatas.ts index 1d2acee..7fc2d9d 100644 --- a/src/hooks/useFormattedDatas.ts +++ b/src/hooks/useFormattedDatas.ts @@ -52,5 +52,5 @@ export function useFormattedDatas(datas: any, fields: any, startTime: any, accum }), ] : formattedSyncedDatas - }, [datas, formattedSyncedDatas, sumFields]) + }, [formattedSyncedDatas, sumFields]) } From 9720209c22de1f48de9b59583860f2949f1c810e Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Mon, 16 Jan 2023 12:58:32 +0300 Subject: [PATCH 11/12] treasury boilerplate --- src/components/GlobalChart/index.js | 1 - src/pages/GlobalPage.js | 44 ++++++++++++++++------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/components/GlobalChart/index.js b/src/components/GlobalChart/index.js index 6c03d55..70f910a 100644 --- a/src/components/GlobalChart/index.js +++ b/src/components/GlobalChart/index.js @@ -45,7 +45,6 @@ export default function GlobalChart({ view }) { false, true ) - console.log(stablesTvl) const barChange = useMemo(() => { if (!allRatios || !allRatios.length > 6) return diff --git a/src/pages/GlobalPage.js b/src/pages/GlobalPage.js index 3598d9a..0302d22 100644 --- a/src/pages/GlobalPage.js +++ b/src/pages/GlobalPage.js @@ -10,7 +10,7 @@ import GlobalChart, { CHART_VIEW } from '../components/GlobalChart' import Search from '../components/Search' import GlobalStats from '../components/GlobalStats' -import { useAllPairsInUniswap, useGlobalData, useTopLps } from '../contexts/GlobalData' +import { useGlobalData } from '../contexts/GlobalData' import { useMedia } from 'react-use' import Panel from '../components/Panel' import { formattedNum, formattedPercent } from '../utils' @@ -19,17 +19,6 @@ import { TYPE, ThemedBackground } from '../Theme' import { PageWrapper, ContentWrapper } from '../components' import { useAllPairData } from '../contexts/PairData' -// const ListOptions = styled(AutoRow)` -// height: 40px; -// width: 100%; -// font-size: 1.25rem; -// font-weight: 600; - -// @media screen and (max-width: 640px) { -// font-size: 1rem; -// } -// ` - const GridRow = styled.div` display: grid; width: 100%; @@ -52,7 +41,6 @@ function GlobalPage() { stableswapLiquidityUSD, fusdLiquidityUSD, } = useGlobalData() - const voltagePrice = '0.00019' const allPairs = useAllPairData() const data = [ @@ -71,6 +59,15 @@ function GlobalPage() { // ...(topLps?.slice(0, 5).map((lp) => [lp.pairName, lp.volumeUSD]) || []), ] + const treasuryData = [ + ['Product', 'TVL in $USD'], + ['VOLT & xVOLT', 500000], + ['Stables & fUSD', 1000000], + ['LPs', 1000000], + ['FUSE', 200000], + ['Other', 200000], + ] + const pairsOptions = { title: 'Top 10 Traded Pairs', pieHole: 0.4, @@ -85,6 +82,13 @@ function GlobalPage() { backgroundColor: '#DDD', color: 'white', } + const treasuryOptions = { + title: 'Voltage Treasury Funds $USD', + pieHole: 0.3, + is3D: true, + backgroundColor: '#DDD', + color: 'white', + } // breakpoints const below800 = useMedia('(max-width: 800px)') @@ -176,12 +180,14 @@ function GlobalPage() { - - - - - - + From c5e0e661ad7348ba8412679897ecfbe7825e65d7 Mon Sep 17 00:00:00 2001 From: Rami Husami Date: Mon, 16 Jan 2023 15:03:19 +0300 Subject: [PATCH 12/12] add treasuries data/ fetch from safe cgw --- src/constants/index.js | 5 ++ src/hooks/useAccountPositionValue.ts | 102 +++++++++++++++++++++++++++ src/pages/GlobalPage.js | 76 ++++++++++---------- 3 files changed, 147 insertions(+), 36 deletions(-) create mode 100644 src/hooks/useAccountPositionValue.ts diff --git a/src/constants/index.js b/src/constants/index.js index b0f171c..677d5a9 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -37,3 +37,8 @@ export const PAIR_BLACKLIST = ['0xb6a741f37d6e455ebcc9f17e2c16d0586c3f57a5'] 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/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/pages/GlobalPage.js b/src/pages/GlobalPage.js index 0302d22..4db1742 100644 --- a/src/pages/GlobalPage.js +++ b/src/pages/GlobalPage.js @@ -1,4 +1,4 @@ -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' @@ -18,6 +18,8 @@ import { TYPE, ThemedBackground } from '../Theme' import { PageWrapper, ContentWrapper } from '../components' import { useAllPairData } from '../contexts/PairData' +import { useTreasuryHoldings } from '../hooks/useAccountPositionValue' +import { TREASURY1, TREASURY2, TREASURY3 } from '../constants' const GridRow = styled.div` display: grid; @@ -33,6 +35,14 @@ function GlobalPage() { // 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, @@ -60,12 +70,34 @@ function GlobalPage() { ] const treasuryData = [ - ['Product', 'TVL in $USD'], - ['VOLT & xVOLT', 500000], - ['Stables & fUSD', 1000000], - ['LPs', 1000000], - ['FUSE', 200000], - ['Other', 200000], + ['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 = { @@ -83,7 +115,7 @@ function GlobalPage() { color: 'white', } const treasuryOptions = { - title: 'Voltage Treasury Funds $USD', + title: `Voltage Treasury Funds $USD ${formattedNum(fiatTotalTreasuries, true)}`, pieHole: 0.3, is3D: true, backgroundColor: '#DDD', @@ -202,34 +234,6 @@ function GlobalPage() { /> - - {/* - - Top Tokens - See All - - - - - - - - Top Pairs - See All - - - - - - - - - Transactions - - - - - */}