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"