import { Bank, PerpMarket } from '@blockworks-foundation/mango-v4' import { LinkButton } from '@components/shared/Button' import ConnectEmptyState from '@components/shared/ConnectEmptyState' import FormatNumericValue from '@components/shared/FormatNumericValue' import SheenLoader from '@components/shared/SheenLoader' import { SortableColumnHeader, Table, TableDateDisplay, Td, Th, TrBody, TrHead, } from '@components/shared/TableElements' import TokenLogo from '@components/shared/TokenLogo' import MarketLogos from '@components/trade/MarketLogos' import { Disclosure, Transition } from '@headlessui/react' import { NoSymbolIcon } from '@heroicons/react/20/solid' import { useWallet } from '@solana/wallet-adapter-react' import mangoStore from '@store/mangoStore' import { useInfiniteQuery } from '@tanstack/react-query' import useMangoAccount from 'hooks/useMangoAccount' import { useSortableData } from 'hooks/useSortableData' import { useViewport } from 'hooks/useViewport' import { useMemo } from 'react' import { useTranslation } from 'react-i18next' import { MarginFundingFeed, isCollateralFundingItem, isPerpFundingItem, } from 'types' import { MANGO_DATA_API_URL, PAGINATION_PAGE_LENGTH } from 'utils/constants' import { breakpoints } from 'utils/theme' type FundingItem = { asset: string amount: number marketOrBank: PerpMarket | Bank | undefined time: string type: string value?: number } export const fetchMarginFunding = async ( mangoAccountPk: string, offset = 0, noLimit?: boolean, ) => { const params = noLimit ? '' : `&limit=${PAGINATION_PAGE_LENGTH}` try { const response = await fetch( `${MANGO_DATA_API_URL}/stats/margin-funding?mango-account=${mangoAccountPk}&offset=${offset}${params}`, ) const parsedResponse = await response.json() if (Array.isArray(parsedResponse)) { return parsedResponse } return [] } catch (e) { console.error('Failed to fetch account margin funding', e) } } const FundingTable = () => { const { t } = useTranslation(['common', 'account']) const { mangoAccountAddress } = useMangoAccount() const { connected } = useWallet() const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false const { data: fundingData, isLoading, // isFetching, isFetchingNextPage, fetchNextPage, } = useInfiniteQuery( ['margin-funding', mangoAccountAddress], ({ pageParam }) => fetchMarginFunding(mangoAccountAddress, pageParam), { cacheTime: 1000 * 60 * 10, staleTime: 1000 * 60 * 5, retry: 3, refetchOnWindowFocus: false, keepPreviousData: true, getNextPageParam: (_lastPage, pages) => pages.length * PAGINATION_PAGE_LENGTH, }, ) const tableData: FundingItem[] = useMemo(() => { if (!fundingData || !fundingData?.pages.length) return [] const group = mangoStore.getState().group const data: FundingItem[] = [] fundingData.pages.flat().forEach((item: MarginFundingFeed) => { const time = item.date_time if (isPerpFundingItem(item)) { const asset = item.activity_details.perp_market const amount = item.activity_details.long_funding + item.activity_details.short_funding const type = 'Perp' const market = group?.getPerpMarketByName(asset) const perpFundingItem = { asset, amount, marketOrBank: market, type, time, } if (Math.abs(amount) > 0) { data.push(perpFundingItem) } } if (isCollateralFundingItem(item)) { const asset = item.activity_details.symbol const amount = item.activity_details.fee_tokens * -1 const value = item.activity_details.fee_value_usd * -1 const type = 'Collateral' const bank = group?.banksMapByName.get(asset)?.[0] const collateralFundingItem = { asset, amount, marketOrBank: bank, type, time, value, } data.push(collateralFundingItem) } }) data.sort((a, b) => new Date(b.time).getTime() - new Date(a.time).getTime()) return data }, [fundingData]) const { items: sortedTableData, requestSort, sortConfig, } = useSortableData(tableData) return mangoAccountAddress && (sortedTableData?.length || isLoading || isFetchingNextPage) ? ( <> {showTableView ? ( {sortedTableData.map((item, i) => { const { asset, amount, marketOrBank, time, type, value } = item return ( ) })}
requestSort('time')} sortConfig={sortConfig} title={t('date')} />
requestSort('asset')} sortConfig={sortConfig} title={t('asset')} />
requestSort('type')} sortConfig={sortConfig} title={t('account:funding-type')} />
requestSort('amount')} sortConfig={sortConfig} title={t('amount')} />
{marketOrBank ? ( marketOrBank instanceof PerpMarket ? ( ) : (
) ) : null}

{asset}

{type}

{type === 'Perp' ? ( 0 ? 'text-th-up' : 'text-th-down' }`} > ) : ( {' '} {asset} {value ? ( ) : null} )}

) : ( sortedTableData.map((item, i) => { const { asset, amount, marketOrBank, time, type, value } = item return ( <>
{marketOrBank ? ( marketOrBank instanceof PerpMarket ? ( ) : (
) ) : null}

{asset}

{type === 'Perp' ? ( 0 ? 'text-th-up' : 'text-th-down' }`} > ) : ( {' '} {asset} {value ? ( ) : null} )}

{t('available')}

) }) )} {isLoading || isFetchingNextPage ? (
{[...Array(20)].map((x, i) => (
))}
) : null} {tableData.length && !(tableData.length % PAGINATION_PAGE_LENGTH) ? ( fetchNextPage()}> {t('show-more')} ) : null} ) : mangoAccountAddress || connected ? (

{t('account:no-funding')}

) : (
) } export default FundingTable