diff --git a/components/shared/DetailedAreaChart.tsx b/components/shared/DetailedAreaChart.tsx index b1876526..c6589b8d 100644 --- a/components/shared/DetailedAreaChart.tsx +++ b/components/shared/DetailedAreaChart.tsx @@ -30,11 +30,11 @@ dayjs.extend(relativeTime) interface DetailedAreaChartProps { data: any[] - daysToShow: string + daysToShow?: string hideChange?: boolean hideChart?: () => void loading?: boolean - setDaysToShow: (x: string) => void + setDaysToShow?: (x: string) => void tickFormat?: (x: any) => string title?: string xKey: string @@ -81,8 +81,9 @@ const DetailedAreaChart: FunctionComponent = ({ const calculateChartChange = () => { if (data.length) { if (mouseData) { + console.log(mouseData) const index = data.findIndex((d: any) => d[xKey] === mouseData[xKey]) - const change = data[index][yKey] - data[0][yKey] + const change = index >= 0 ? data[index][yKey] - data[0][yKey] : 0 return isNaN(change) ? 0 : change } else return data[data.length - 1][yKey] - data[0][yKey] } @@ -105,9 +106,11 @@ const DetailedAreaChart: FunctionComponent = ({
- - - + {hideChart ? ( + + + + ) : null}

{title}

{mouseData ? ( @@ -179,14 +182,16 @@ const DetailedAreaChart: FunctionComponent = ({
-
- setDaysToShow(v)} - /> -
+ {setDaysToShow ? ( +
+ setDaysToShow(v)} + /> +
+ ) : null}
{children}
diff --git a/components/stats/TokenStats.tsx b/components/stats/TokenStats.tsx index 60c2e7d0..dd2a5459 100644 --- a/components/stats/TokenStats.tsx +++ b/components/stats/TokenStats.tsx @@ -6,36 +6,72 @@ import { } from '@heroicons/react/20/solid' import { useTranslation } from 'next-i18next' import Image from 'next/legacy/image' -import { Fragment, useMemo, useState } from 'react' +import { Fragment, useEffect, useMemo, useState } from 'react' import { useViewport } from '../../hooks/useViewport' import { formatDecimal, formatFixedDecimals } from '../../utils/numbers' import { breakpoints } from '../../utils/theme' import { IconButton, LinkButton } from '../shared/Button' import ContentBox from '../shared/ContentBox' -import FlipNumbers from 'react-flip-numbers' import Tooltip from '@components/shared/Tooltip' import { Bank } from '@blockworks-foundation/mango-v4' import { useRouter } from 'next/router' import useJupiterMints from 'hooks/useJupiterMints' import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements' import useMangoGroup from 'hooks/useMangoGroup' -import useLocalStorageState from 'hooks/useLocalStorageState' -import { ANIMATION_SETTINGS_KEY } from 'utils/constants' -import { INITIAL_ANIMATION_SETTINGS } from '@components/settings/AnimationSettings' +import dayjs from 'dayjs' +import mangoStore, { TokenStatsItem } from '@store/mangoStore' +import SheenLoader from '@components/shared/SheenLoader' +import dynamic from 'next/dynamic' +const DetailedAreaChart = dynamic( + () => import('@components/shared/DetailedAreaChart'), + { ssr: false } +) + +interface TotalValueItem { + date: string + borrowValue: number + depositValue: number +} const TokenStats = () => { const { t } = useTranslation(['common', 'token']) + const actions = mangoStore((s) => s.actions) + const tokenStats = mangoStore((s) => s.tokenStats.data) + const loadingStats = mangoStore((s) => s.tokenStats.loading) const [showTokenDetails, setShowTokenDetails] = useState('') const { group } = useMangoGroup() const { mangoTokens } = useJupiterMints() const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false const router = useRouter() - const [animationSettings] = useLocalStorageState( - ANIMATION_SETTINGS_KEY, - INITIAL_ANIMATION_SETTINGS - ) + + useEffect(() => { + actions.fetchTokenStats() + }, [group]) + + const totalValues = useMemo(() => { + if (!tokenStats.length) return [] + const values: TotalValueItem[] = tokenStats.reduce( + (a: TotalValueItem[], c: TokenStatsItem) => { + const hasDate = a.find((d: TotalValueItem) => d.date === c.date_hour) + if (!hasDate) { + a.push({ + date: c.date_hour, + depositValue: c.total_deposits * c.price, + borrowValue: c.total_borrows * c.price, + }) + } else { + hasDate.depositValue = + hasDate.depositValue + c.total_deposits * c.price + hasDate.borrowValue = hasDate.borrowValue + c.total_borrows * c.price + } + return a + }, + [] + ) + return values.reverse() + }, [tokenStats]) const banks = useMemo(() => { if (group) { @@ -75,44 +111,55 @@ const TokenStats = () => { return (
-
-

- {t('total-deposit-value')} -

-
- {animationSettings['number-scroll'] ? ( - - ) : ( -

{formatFixedDecimals(totalDepositValue || 0.0, true)}

- )} + {loadingStats ? ( +
+ +
+
-
-
-

- {t('total-borrow-value')} -

-
- {animationSettings['number-scroll'] ? ( - - ) : ( - {formatFixedDecimals(totalBorrowValue || 0.0, true)} - )} + ) : totalValues.length ? ( +
+ `$${x.toFixed(2)}`} + title={t('total-deposit-value')} + xKey="date" + yKey={'depositValue'} + />
-
+ ) : null} + {loadingStats ? ( +
+ +
+ +
+ ) : totalValues.length ? ( +
+ console.log('fuck')} + tickFormat={(x) => `$${x.toFixed(2)}`} + title={t('total-borrow-value')} + xKey="date" + yKey={'borrowValue'} + /> +
+ ) : null}
{showTableView ? ( diff --git a/store/mangoStore.ts b/store/mangoStore.ts index b7c662aa..7b4b55d2 100644 --- a/store/mangoStore.ts +++ b/store/mangoStore.ts @@ -37,6 +37,7 @@ import { Orderbook, SpotBalances } from 'types' import spotBalancesUpdater from './spotBalancesUpdater' import { PerpMarket } from '@blockworks-foundation/mango-v4/' import perpPositionsUpdater from './perpPositionsUpdater' +import { token } from '@project-serum/anchor/dist/cjs/utils' const GROUP = new PublicKey('DLdcpC6AsAJ9xeKMR3WhHrN5sM5o7GVVXQhQ5vwisTtz') @@ -144,6 +145,21 @@ interface TourSettings { wallet_pk: string } +export interface TokenStatsItem { + borrow_apr: number + borrow_rate: number + collected_fees: number + date_hour: string + deposit_apr: number + deposit_rate: number + mango_group: string + price: number + symbol: string + token_index: number + total_borrows: number + total_deposits: number +} + // const defaultUserSettings = { // account_tour_seen: false, // default_language: 'English', @@ -218,6 +234,10 @@ export type MangoStore = { success: boolean } set: (x: (x: MangoStore) => void) => void + tokenStats: { + loading: boolean + data: TokenStatsItem[] + } tradeForm: { side: 'buy' | 'sell' price: string @@ -252,6 +272,7 @@ export type MangoStore = { fetchOpenOrders: (ma?: MangoAccount) => Promise fetchProfileDetails: (walletPk: string) => void fetchSwapHistory: (mangoAccountPk: string) => Promise + fetchTokenStats: () => void fetchTourSettings: (walletPk: string) => void fetchWalletTokens: (wallet: Wallet) => Promise connectMangoClientWithWallet: (wallet: WalletAdapter) => Promise @@ -321,6 +342,10 @@ const mangoStore = create()( }, uiLocked: true, }, + tokenStats: { + loading: false, + data: [], + }, tradeForm: { side: 'buy', price: '', @@ -722,6 +747,34 @@ const mangoStore = create()( }) } }, + fetchTokenStats: async () => { + const set = get().set + const group = get().group + const stats = get().tokenStats.data + if (stats.length || !group) return + set((state) => { + state.tokenStats.loading = true + }) + try { + const response = await fetch( + `https://mango-transaction-log.herokuapp.com/v4/token-historical-stats?mango-group=${group?.publicKey.toString()}` + ) + const data = await response.json() + + set((state) => { + state.tokenStats.data = data + state.tokenStats.loading = false + }) + } catch { + set((state) => { + state.tokenStats.loading = false + }) + notify({ + title: 'Failed to token stats data', + type: 'error', + }) + } + }, fetchWalletTokens: async (wallet: Wallet) => { const set = get().set const connection = get().connection