import { I80F48 } from '@blockworks-foundation/mango-client' import Chart from '../Chart' import { tokenPrecision } from '../../utils' import { useViewport } from '../../hooks/useViewport' import { breakpoints } from '../TradePageGrid' import { Table, Td, Th, TrBody, TrHead } from '../TableElements' import { ExpandableRow, Row } from '../TableElements' import { useTranslation } from 'next-i18next' import { useMemo } from 'react' interface Values { name: string value: number time: string } interface Points { value: number time: string } function formatNumberString(x: number, decimals): string { return new Intl.NumberFormat('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals, }).format(x) } const getAverageStats = ( stats: any[], daysAgo: number, symbol: string, type: string ): string => { if (stats.length > 0) { const priorDate = new Date(Date.now() - daysAgo * 24 * 60 * 60 * 1000) const selectedStatsData = stats.filter((s) => s.name === symbol) const timeFilteredStats = selectedStatsData.filter( (d) => new Date(d.time).getTime() >= priorDate.getTime() ) const oldestStat = timeFilteredStats[0] const latestStat = timeFilteredStats[timeFilteredStats.length - 1] let avg if (latestStat && oldestStat && type in latestStat && type in oldestStat) { avg = Math.pow(latestStat[type] / oldestStat[type], 365 / daysAgo) * 100 - 100 } priorDate.setHours(priorDate.getHours() + 1) if (new Date(oldestStat?.hourly).getDate() > priorDate.getDate()) { return '-' } if (avg) { return `${avg.toFixed(4)}%` } } return '-' } export default function StatsTotals({ latestStats, stats, loadHistoricalStats, loadLatestStats, }) { const { t } = useTranslation('common') const { width } = useViewport() const isMobile = width ? width < breakpoints.sm : false // get deposit and borrow values from stats const [depositValues, borrowValues]: [Values[], Values[]] = useMemo(() => { const depositValues: Values[] = [] const borrowValues: Values[] = [] for (let i = 0; i < stats?.length; i++) { const time = stats[i].hourly const name = stats[i].name const depositValue = stats[i].name === 'USDC' ? stats[i].totalDeposits : stats[i].totalDeposits * stats[i].baseOraclePrice const borrowValue = stats[i].name === 'USDC' ? stats[i].totalBorrows : stats[i].totalBorrows * stats[i].baseOraclePrice if (typeof depositValue === 'number' && name && time) { depositValues.push({ name, value: depositValue, time, }) } if (typeof borrowValue === 'number' && name && time) { borrowValues.push({ name, value: borrowValue, time, }) } } return [depositValues, borrowValues] }, [stats]) const formatValues = (values) => { // get value for each symbol every hour const hours = values.reduce((acc, d) => { const found = acc.find((a) => a.time === d.time && a.name === d.name) const value = { value: d.value, name: d.name, time: d.time, } if (!found) { acc.push(value) } else { found.value = d.value } return acc }, []) // sum the values for each hour const holder = {} hours.forEach(function (d) { if (d.time in holder) { holder[d.time] = holder[d.time] + d.value } else { holder[d.time] = d.value } }) const points: Points[] = [] for (const prop in holder) { points.push({ time: prop, value: holder[prop] }) } return points } return ( <>
x && '$' + x.toLocaleString(undefined, { maximumFractionDigits: 0 }) } type="area" loading={loadHistoricalStats} />
x && '$' + x.toLocaleString(undefined, { maximumFractionDigits: 0 }) } type="area" loading={loadHistoricalStats} />
{!isMobile ? ( <>

{t('current-stats')}

{latestStats.length > 0 ? ( {latestStats.map((stat) => ( ))}
{t('asset')} {t('total-deposits')} {t('total-borrows')} {t('deposit-rate')} {t('borrow-rate')} {t('utilization')}
{stat.name}
{formatNumberString( stat.totalDeposits, tokenPrecision[stat.name] )} {formatNumberString( stat.totalBorrows, tokenPrecision[stat.name] )} {formatNumberString( stat.depositInterest.toNumber(), 2 )} % {formatNumberString( stat.borrowInterest.toNumber(), 2 )} % {formatNumberString( stat.utilization .mul(I80F48.fromNumber(100)) .toNumber(), 2 )} %
) : loadLatestStats ? ( <>
) : null}

{t('average-deposit')}

{stats?.length && latestStats?.length ? ( {latestStats.map((stat) => ( ))}
{t('asset')} 24h 7d 30d
{stat.name}
{getAverageStats(stats, 1, stat.name, 'depositIndex')} {getAverageStats(stats, 7, stat.name, 'depositIndex')} {getAverageStats(stats, 30, stat.name, 'depositIndex')}
) : loadHistoricalStats || loadLatestStats ? ( <>
) : null}
<>

{t('average-borrow')}

{stats?.length && latestStats?.length ? ( {latestStats.map((stat) => ( ))}
{t('asset')} 24h 7d 30d
{stat.name}
{getAverageStats(stats, 1, stat.name, 'borrowIndex')} {getAverageStats(stats, 7, stat.name, 'borrowIndex')} {getAverageStats(stats, 30, stat.name, 'borrowIndex')}
) : loadHistoricalStats || loadLatestStats ? ( <>
) : null} ) : ( <>

{t('current-stats')}

{latestStats.length ? ( latestStats.map((stat) => (
{stat.name}
{t('total-deposits')}
{formatNumberString(stat.totalDeposits, 0)}
{t('total-borrows')}
{formatNumberString(stat.totalBorrows, 0)}
} key={stat.name} panelTemplate={
{t('deposit-rate')}
{formatNumberString( stat.depositInterest.toNumber(), 2 )} %
{t('borrow-rate')}
{formatNumberString( stat.borrowInterest.toNumber(), 2 )} %
{t('utilization')}
{formatNumberString( stat.utilization .mul(I80F48.fromNumber(100)) .toNumber(), 2 )} %
} /> )) ) : loadLatestStats ? ( <>
) : null}
{stats.length && latestStats.length ? (

{t('average-deposit')}

{latestStats.map((stat) => (
{stat.name}
24h
{getAverageStats(stats, 1, stat.name, 'depositIndex')}
7d
{getAverageStats(stats, 7, stat.name, 'depositIndex')}
30d
{getAverageStats(stats, 30, stat.name, 'depositIndex')}
))}
) : loadHistoricalStats || loadLatestStats ? ( <>
) : null} {stats.length && latestStats.length ? (

{t('average-borrow')}

{latestStats.map((stat) => (
{stat.name}
24h
{getAverageStats(stats, 1, stat.name, 'borrowIndex')}
7d
{getAverageStats(stats, 7, stat.name, 'borrowIndex')}
30d
{getAverageStats(stats, 30, stat.name, 'borrowIndex')}
))}
) : loadHistoricalStats || loadLatestStats ? ( <>
) : null} )} ) }