From dc10d611d05bc7451f9a1f47e0149db769a35067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezi=C5=84ski?= Date: Fri, 15 Mar 2024 14:03:59 +0100 Subject: [PATCH] Feature/fix token history request v2 (#403) * fix large token stats request * fix * upgrade settings lib * fix * fix * fix * fix * fix cd * test * fix build --- apis/mngo/index.ts | 15 +++--- components/governance/ListToken/ListToken.tsx | 2 +- .../modals/DashboardSuggestedValuesModal.tsx | 4 +- components/stats/mango/DepositsAndBorrows.tsx | 24 ++++------ components/stats/mango/Fees.tsx | 9 ++-- components/token/ChartTabs.tsx | 29 ++++-------- hooks/useTokenStats.ts | 38 +++++++++++++++ package.json | 7 ++- store/mangoStore.ts | 46 ------------------- utils/constants.ts | 2 +- utils/tokens.ts | 1 + yarn.lock | 8 ++-- 12 files changed, 83 insertions(+), 102 deletions(-) create mode 100644 hooks/useTokenStats.ts diff --git a/apis/mngo/index.ts b/apis/mngo/index.ts index 9d34125e..4cbfc06f 100644 --- a/apis/mngo/index.ts +++ b/apis/mngo/index.ts @@ -1,11 +1,14 @@ -import { Group, I64_MAX_BN } from '@blockworks-foundation/mango-v4' +import { Group } from '@blockworks-foundation/mango-v4' +import { PublicKey } from '@solana/web3.js' import { MangoTokenStatsItem, TokenStatsItem } from 'types' import { MANGO_DATA_API_URL } from 'utils/constants' -export const fetchTokenStatsData = async (group: Group) => { - const response = await fetch( - `${MANGO_DATA_API_URL}/token-historical-stats?mango-group=${group?.publicKey.toString()}`, - ) +export const fetchTokenStatsData = async (group: Group, mint?: PublicKey) => { + let url = `${MANGO_DATA_API_URL}/token-historical-stats?mango-group=${group?.publicKey.toString()}` + if (mint) { + url = `${url}&mint=${mint.toBase58()}` + } + const response = await fetch(url) if (!response.ok) { throw new Error('Network response was not ok') } @@ -52,7 +55,7 @@ export const processTokenStatsData = ( const previous = filtered.reduce((max, cur) => max.date_hour > cur.date_hour ? max : cur, ) - let tokenStatsItem: TokenStatsItem = { + const tokenStatsItem: TokenStatsItem = { borrow_apr: previous.borrow_apr, borrow_rate: bank.getBorrowRateUi() / 100, collected_fees: previous.collected_fees, diff --git a/components/governance/ListToken/ListToken.tsx b/components/governance/ListToken/ListToken.tsx index 6f74abe6..3fa95ce2 100644 --- a/components/governance/ListToken/ListToken.tsx +++ b/components/governance/ListToken/ListToken.tsx @@ -573,7 +573,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { new BN(proposedPreset.depositLimit.toString()), Number(proposedPreset.zeroUtilRate), Number(proposedPreset.platformLiquidationFee), - false, + proposedPreset.disableAssetLiquidation, Number(proposedPreset.collateralFeePerDay), ) .accounts({ diff --git a/components/modals/DashboardSuggestedValuesModal.tsx b/components/modals/DashboardSuggestedValuesModal.tsx index 3ea8ad55..c99fbef0 100644 --- a/components/modals/DashboardSuggestedValuesModal.tsx +++ b/components/modals/DashboardSuggestedValuesModal.tsx @@ -208,7 +208,9 @@ const DashboardSuggestedValues = ({ : null, getNullOrVal(fieldsToChange.zeroUtilRate), getNullOrVal(fieldsToChange.platformLiquidationFee), - null, + fieldsToChange.disableAssetLiquidation === undefined + ? null + : fieldsToChange.disableAssetLiquidation, getNullOrVal(fieldsToChange.collateralFeePerDay), null, ) diff --git a/components/stats/mango/DepositsAndBorrows.tsx b/components/stats/mango/DepositsAndBorrows.tsx index a7bbc09d..f7e773e1 100644 --- a/components/stats/mango/DepositsAndBorrows.tsx +++ b/components/stats/mango/DepositsAndBorrows.tsx @@ -1,34 +1,26 @@ -import mangoStore from '@store/mangoStore' import { useTranslation } from 'next-i18next' -import { useEffect, useState } from 'react' +import { useState } from 'react' import { formatYAxis } from 'utils/formatting' import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart' import NetDepositsChart from './NetDepositsChart' +import { useTokenStats } from 'hooks/useTokenStats' const DepositsAndBorrows = () => { const { t } = useTranslation(['common', 'token', 'trade']) - const mangoStats = mangoStore((s) => s.tokenStats.mangoStats) - const loadingStats = mangoStore((s) => s.tokenStats.loading) + + const { data: tokenStats, isLoading } = useTokenStats() const [borrowDaysToShow, setBorrowDaysToShow] = useState('30') const [depositDaysToShow, setDepositDaysToShow] = useState('30') - const tokenStatsInitialLoad = mangoStore((s) => s.tokenStats.initialLoad) - - useEffect(() => { - if (!tokenStatsInitialLoad) { - const actions = mangoStore.getState().actions - actions.fetchTokenStats() - } - }, [tokenStatsInitialLoad]) return ( <>
{
`$${formatYAxis(x)}`} title={t('total-borrow-value')} diff --git a/components/stats/mango/Fees.tsx b/components/stats/mango/Fees.tsx index e83b22be..c3301c1f 100644 --- a/components/stats/mango/Fees.tsx +++ b/components/stats/mango/Fees.tsx @@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next' import { MangoTokenStatsItem } from 'types' import { formatYAxis } from 'utils/formatting' import { groupPerpByHourlyInterval } from './Volume' +import { useTokenStats } from 'hooks/useTokenStats' interface GroupedTokenDataItem extends MangoTokenStatsItem { intervalStartMillis: number @@ -42,8 +43,8 @@ const groupTokenByHourlyInterval = ( const Fees = () => { const { t } = useTranslation(['common', 'token', 'trade']) - const mangoStats = mangoStore((s) => s.tokenStats.mangoStats) - const loadingStats = mangoStore((s) => s.tokenStats.loading) + const { data: tokenStats, isLoading } = useTokenStats() + const mangoStats = tokenStats?.mangoStats const loadingPerpStats = mangoStore((s) => s.perpStats.loading) const [feesDaysToShow, setFeesDaysToShow] = useState('30') const [showCumulativeFees, setShowCumulativeFees] = useState(true) @@ -52,7 +53,7 @@ const Fees = () => { const { feeValues: perpFeeChartData } = usePerpStatsChartData() const tokenFeesChartData = useMemo(() => { - if (!mangoStats.length) return [] + if (!mangoStats?.length) return [] if (showCumulativeFees) { return mangoStats } else { @@ -115,7 +116,7 @@ const Fees = () => { setDaysToShow={setFeesDaysToShow} heightClass="h-64" loaderHeightClass="h-[350px]" - loading={loadingStats} + loading={isLoading} prefix="$" tickFormat={(x) => `$${formatYAxis(x)}`} title={t('token:token-fees-collected')} diff --git a/components/token/ChartTabs.tsx b/components/token/ChartTabs.tsx index f08bc61a..5ce4f2e8 100644 --- a/components/token/ChartTabs.tsx +++ b/components/token/ChartTabs.tsx @@ -1,13 +1,13 @@ import { Bank } from '@blockworks-foundation/mango-v4' import TabButtons from '@components/shared/TabButtons' -import mangoStore from '@store/mangoStore' import { useTranslation } from 'next-i18next' -import { useEffect, useMemo, useState } from 'react' +import { useMemo, useState } from 'react' import { TokenStatsItem } from 'types' import { formatYAxis } from 'utils/formatting' import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart' import TokenRatesChart from './TokenRatesChart' import Switch from '@components/forms/Switch' +import { useTokenStats } from 'hooks/useTokenStats' const SWITCH_WRAPPER_CLASSES = 'mt-4 flex justify-end space-x-4 border-t border-th-bkg-3 px-4 py-2 md:px-6' @@ -71,20 +71,11 @@ const ChartTabs = ({ bank }: { bank: Bank }) => { const [borrowDaysToShow, setBorrowDaysToShow] = useState('30') const [depositRateDaysToShow, setDepositRateDaysToShow] = useState('30') const [borrowRateDaysToShow, setBorrowRateDaysToShow] = useState('30') - const tokenStats = mangoStore((s) => s.tokenStats.data) - const loadingTokenStats = mangoStore((s) => s.tokenStats.loading) - const tokenStatsInitialLoad = mangoStore((s) => s.tokenStats.initialLoad) - - useEffect(() => { - if (!tokenStatsInitialLoad) { - const actions = mangoStore.getState().actions - actions.fetchTokenStats() - } - }, [tokenStatsInitialLoad]) - + const { data: tokenStats, isLoading } = useTokenStats(bank.mint) + console.log(tokenStats) const formattedStats = useMemo(() => { - if (!tokenStats?.length) return [] - return tokenStats + if (!tokenStats?.data?.length) return [] + return tokenStats.data .filter((c) => c.token_index === bank.tokenIndex) .sort( (a, b) => @@ -192,7 +183,7 @@ const ChartTabs = ({ bank }: { bank: Bank }) => { heightClass="h-64" loaderHeightClass="h-[334px]" domain={[0, 'dataMax']} - loading={loadingTokenStats} + loading={isLoading} small tickFormat={(x) => formatYAxis(x)} title={`${t('token:deposits')}`} @@ -229,7 +220,7 @@ const ChartTabs = ({ bank }: { bank: Bank }) => { data={formattedStats} dataKey="deposit_apr" daysToShow={depositRateDaysToShow} - loading={loadingTokenStats} + loading={isLoading} setDaysToShow={setDepositRateDaysToShow} title={`${t('token:average-deposit-rate')} (APR)`} /> @@ -270,7 +261,7 @@ const ChartTabs = ({ bank }: { bank: Bank }) => { heightClass="h-64" loaderHeightClass="h-[334px]" domain={[0, 'dataMax']} - loading={loadingTokenStats} + loading={isLoading} small tickFormat={(x) => formatYAxis(x)} title={`${t('token:borrows')}`} @@ -307,7 +298,7 @@ const ChartTabs = ({ bank }: { bank: Bank }) => { data={formattedStats} dataKey="borrow_apr" daysToShow={borrowRateDaysToShow} - loading={loadingTokenStats} + loading={isLoading} setDaysToShow={setBorrowRateDaysToShow} title={`${t('token:average-borrow-rate')} (APR)`} /> diff --git a/hooks/useTokenStats.ts b/hooks/useTokenStats.ts new file mode 100644 index 00000000..b42ae84a --- /dev/null +++ b/hooks/useTokenStats.ts @@ -0,0 +1,38 @@ +import { useQuery } from '@tanstack/react-query' +import { fetchTokenStatsData, processTokenStatsData } from 'apis/mngo' +import useMangoGroup from './useMangoGroup' +import { PublicKey } from '@solana/web3.js' + +const refetchMs = 24 * 60 * 60 * 1000 + +export function useTokenStats(mint?: PublicKey) { + const { group } = useMangoGroup() + const criteria = mint + ? [group?.publicKey.toBase58(), mint.toBase58()] + : [group?.publicKey.toBase58(), 'all'] + + return useQuery( + ['tokenStats', criteria], + async () => { + try { + const rawData = await fetchTokenStatsData(group!, mint) + const [data, mangoStats] = processTokenStatsData(rawData, group!) + return { + data, + mangoStats, + } + } catch (error) { + return { + data: [], + mangoStats: [], + } + } + }, + { + enabled: !!group && mint ? !!mint : !!'all', + staleTime: refetchMs, + retry: 1, + refetchInterval: refetchMs, + }, + ) +} diff --git a/package.json b/package.json index f992088f..fdb46514 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,9 @@ "version": "0.1.0", "private": true, "scripts": { - "setup": "yarn install --network-concurrency 1 && npx yarn-deduplicate && yarn allow-scripts && yarn bigint-fix", - "ci": "yarn install --frozen-lockfile --network-concurrency 1 --color=always && yarn allow-scripts && yarn bigint-fix", + "setup": "yarn install --network-concurrency 1 && npx yarn-deduplicate && yarn allow-scripts", + "ci": "yarn install --frozen-lockfile --network-concurrency 1 --color=always && yarn allow-scripts", "ci-dupe-check": "npx yarn-deduplicate --list --fail", - "bigint-fix": "cd node_modules/bigint-buffer && yarn rebuild && cd ../../", "dev": "rm -rf .next && next dev", "test": "yarn jest", "build": "next build", @@ -25,7 +24,7 @@ "@blockworks-foundation/mango-feeds": "0.1.7", "@blockworks-foundation/mango-mints-redemption": "^0.0.10", "@blockworks-foundation/mango-v4": "0.23.1", - "@blockworks-foundation/mango-v4-settings": "0.14.17", + "@blockworks-foundation/mango-v4-settings": "0.14.19", "@blockworks-foundation/mangolana": "0.0.14", "@headlessui/react": "1.6.6", "@heroicons/react": "2.0.18", diff --git a/store/mangoStore.ts b/store/mangoStore.ts index a75b5abb..6046ea56 100644 --- a/store/mangoStore.ts +++ b/store/mangoStore.ts @@ -59,10 +59,8 @@ import { SpotTradeHistory, SwapHistoryItem, TradeForm, - TokenStatsItem, NFT, TourSettings, - MangoTokenStatsItem, ThemeData, PositionStat, OrderbookTooltip, @@ -81,7 +79,6 @@ import { IOrderLineAdapter, } from '@public/charting_library/charting_library' import { nftThemeMeta } from 'utils/theme' -import { fetchTokenStatsData, processTokenStatsData } from 'apis/mngo' import { OrderTypes } from 'utils/tradeForm' import { usePlausible } from 'next-plausible' import { collectTxConfirmationData } from 'utils/transactionConfirmationData' @@ -276,12 +273,6 @@ export type MangoStore = { } set: (x: (x: MangoStore) => void) => void themeData: ThemeData - tokenStats: { - initialLoad: boolean - loading: boolean - data: TokenStatsItem[] | null - mangoStats: MangoTokenStatsItem[] - } tradeForm: TradeForm tradingView: { orderLines: Map @@ -320,7 +311,6 @@ export type MangoStore = { offset?: number, limit?: number, ) => Promise - fetchTokenStats: () => void fetchTourSettings: (walletPk: string) => void fetchWalletTokens: (walletPk: PublicKey) => Promise connectMangoClientWithWallet: (wallet: WalletAdapter) => Promise @@ -472,12 +462,6 @@ const mangoStore = create()( triggerPrice: '', }, themeData: nftThemeMeta.default, - tokenStats: { - initialLoad: false, - loading: true, - data: [], - mangoStats: [], - }, tradeForm: DEFAULT_TRADE_FORM, tradingView: { orderLines: new Map(), @@ -956,36 +940,6 @@ const mangoStore = create()( } }, timeout) }, - fetchTokenStats: async () => { - const set = get().set - const group = get().group - if (!group) return - - set((state) => { - state.tokenStats.loading = true - }) - - try { - const rawData = await fetchTokenStatsData(group) - const [data, mangoStats] = processTokenStatsData(rawData, group) - - set((state) => { - state.tokenStats.data = data - state.tokenStats.mangoStats = mangoStats - state.tokenStats.initialLoad = true - state.tokenStats.loading = false - }) - } catch (error) { - set((state) => { - state.tokenStats.loading = false - }) - console.log('Failed to fetch token stats data', error) - notify({ - title: 'Failed to fetch token stats data', - type: 'error', - }) - } - }, fetchWalletTokens: async (walletPk: PublicKey) => { const set = get().set const connection = get().connection diff --git a/utils/constants.ts b/utils/constants.ts index 4cfba313..b44c4d63 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -1,4 +1,4 @@ -import { PublicKey } from '@metaplex-foundation/js' +import { PublicKey } from '@solana/web3.js' export const LAST_ACCOUNT_KEY = 'mangoAccount-0.4' diff --git a/utils/tokens.ts b/utils/tokens.ts index 73f15996..f9530b71 100644 --- a/utils/tokens.ts +++ b/utils/tokens.ts @@ -106,6 +106,7 @@ function loadNft( return Promise.race([ metaplex .nfts() + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore .load({ metadata: nft }) .catch((e) => { diff --git a/yarn.lock b/yarn.lock index 654f6c25..c9f8a06d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -350,10 +350,10 @@ bn.js "^5.2.1" eslint-config-prettier "^9.0.0" -"@blockworks-foundation/mango-v4-settings@0.14.17": - version "0.14.17" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.14.17.tgz#789d5c8b69f37881331acf30c855164b73892be5" - integrity sha512-Cu+85KSBm+G3ELNgnu8hd398swm4rinHrqMN4mSe9BHCwkMZBnxg8bynCYu2xpgbWTXEqdooyXQbBN0t3OZkHg== +"@blockworks-foundation/mango-v4-settings@0.14.19": + version "0.14.19" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.14.19.tgz#5f712a04cb34a7f12cbc742002cef1c5c3efb887" + integrity sha512-F01JfWnRHczrTidgHRyUwOacH1arC6pcLD9KGEvghdEE5YgetRBbrbAiFfrPQ4axym2ovX6HByVb1zAouDnoow== dependencies: bn.js "^5.2.1" eslint-config-prettier "^9.0.0"