2022-08-23 15:33:09 -07:00
import { Transition } from '@headlessui/react'
2022-09-06 21:36:35 -07:00
import {
ChevronDownIcon ,
2022-10-11 04:59:01 -07:00
ChevronRightIcon ,
2022-09-06 21:36:35 -07:00
QuestionMarkCircleIcon ,
} from '@heroicons/react/20/solid'
2022-08-23 15:33:09 -07:00
import { useTranslation } from 'next-i18next'
2022-10-28 14:46:38 -07:00
import Image from 'next/legacy/image'
2023-01-29 20:13:38 -08:00
import { Fragment , useEffect , useState } from 'react'
2022-08-23 15:33:09 -07:00
import { useViewport } from '../../hooks/useViewport'
import { breakpoints } from '../../utils/theme'
2023-03-18 04:21:48 -07:00
import { LinkButton } from '../shared/Button'
2022-08-23 15:33:09 -07:00
import ContentBox from '../shared/ContentBox'
2022-09-24 05:28:11 -07:00
import Tooltip from '@components/shared/Tooltip'
2023-03-18 04:21:48 -07:00
import { Bank , toUiDecimals } from '@blockworks-foundation/mango-v4'
2022-10-11 04:59:01 -07:00
import { useRouter } from 'next/router'
2022-11-18 11:11:06 -08:00
import useJupiterMints from 'hooks/useJupiterMints'
2022-11-20 02:44:14 -08:00
import { Table , Td , Th , TrBody , TrHead } from '@components/shared/TableElements'
2022-11-20 12:32:38 -08:00
import useMangoGroup from 'hooks/useMangoGroup'
2022-12-20 00:16:05 -08:00
import mangoStore from '@store/mangoStore'
2023-01-24 02:42:26 -08:00
import FormatNumericValue from '@components/shared/FormatNumericValue'
2023-01-28 17:13:36 -08:00
import BankAmountWithValue from '@components/shared/BankAmountWithValue'
2023-01-29 20:13:38 -08:00
import useBanksWithBalances from 'hooks/useBanksWithBalances'
2023-02-16 02:56:05 -08:00
import Decimal from 'decimal.js'
2022-08-23 15:33:09 -07:00
2022-10-11 04:59:01 -07:00
const TokenStats = ( ) = > {
const { t } = useTranslation ( [ 'common' , 'token' ] )
2023-01-03 14:20:00 -08:00
const actions = mangoStore . getState ( ) . actions
2022-12-11 02:08:50 -08:00
const initialStatsLoad = mangoStore ( ( s ) = > s . tokenStats . initialLoad )
2022-08-23 15:33:09 -07:00
const [ showTokenDetails , setShowTokenDetails ] = useState ( '' )
2022-11-20 12:32:38 -08:00
const { group } = useMangoGroup ( )
2022-11-18 11:11:06 -08:00
const { mangoTokens } = useJupiterMints ( )
2022-08-23 15:33:09 -07:00
const { width } = useViewport ( )
const showTableView = width ? width > breakpoints.md : false
2022-10-11 04:59:01 -07:00
const router = useRouter ( )
2023-01-29 20:13:38 -08:00
const banks = useBanksWithBalances ( )
2022-12-05 19:23:22 -08:00
useEffect ( ( ) = > {
2022-12-11 02:08:50 -08:00
if ( group && ! initialStatsLoad ) {
2022-12-06 03:58:22 -08:00
actions . fetchTokenStats ( )
}
2022-12-05 19:23:22 -08:00
} , [ group ] )
2023-03-18 04:21:48 -07:00
const handleShowTokenDetails = ( bank : Bank ) = > {
showTokenDetails === bank . name
? setShowTokenDetails ( '' )
: setShowTokenDetails ( bank . name )
2022-08-23 15:33:09 -07:00
}
2022-10-11 04:59:01 -07:00
const goToTokenPage = ( bank : Bank ) = > {
router . push ( ` /token/ ${ bank . name } ` , undefined , { shallow : true } )
}
2023-02-16 02:56:05 -08:00
return group ? (
2022-09-14 19:41:55 -07:00
< ContentBox hideBorder hidePadding >
2022-08-23 15:33:09 -07:00
{ showTableView ? (
2023-03-18 04:21:48 -07:00
< div className = "thin-scroll overflow-x-auto" >
< Table >
< thead >
< TrHead >
< Th className = "text-left" > { t ( 'token' ) } < / Th >
< Th className = "text-right" > { t ( 'total-deposits' ) } < / Th >
< Th className = "text-right" > { t ( 'total-borrows' ) } < / Th >
< Th className = "text-right" >
< div className = "flex justify-end" >
< Tooltip content = "The amount available to borrow" >
< span className = "tooltip-underline" >
{ t ( 'available' ) }
< / span >
< / Tooltip >
< / div >
< / Th >
< Th >
< div className = "flex justify-end" >
< Tooltip content = "Fees collected for loan originations" >
< span className = "tooltip-underline" > { t ( 'fees' ) } < / span >
< / Tooltip >
< / div >
< / Th >
< Th >
< div className = "flex justify-end" >
< Tooltip content = "The deposit rate (green) will automatically be paid on positive balances and the borrow rate (red) will automatically be charged on negative balances." >
< span className = "tooltip-underline" > { t ( 'rates' ) } < / span >
< / Tooltip >
< / div >
< / Th >
< Th >
< div className = "flex justify-end" >
< Tooltip content = "The percentage of deposits that have been lent out" >
< span className = "tooltip-underline" >
{ t ( 'utilization' ) }
< / span >
< / Tooltip >
< / div >
< / Th >
< Th >
< div className = "flex justify-end text-right" >
< Tooltip content = { t ( 'asset-liability-weight-desc' ) } >
< span className = "tooltip-underline" >
{ t ( 'asset-liability-weight' ) }
< / span >
< / Tooltip >
< / div >
< / Th >
< Th / >
< / TrHead >
< / thead >
< tbody >
{ banks . map ( ( b ) = > {
const bank : Bank = b . bank
2023-01-03 01:20:34 -08:00
2023-03-18 04:21:48 -07:00
let logoURI
if ( mangoTokens ? . length ) {
logoURI = mangoTokens . find (
( t ) = > t . address === bank . mint . toString ( )
) ? . logoURI
}
const deposits = bank . uiDeposits ( )
const borrows = bank . uiBorrows ( )
const availableVaultBalance =
group . getTokenVaultBalanceByMintUi ( bank . mint ) -
deposits * bank . minVaultToDepositsRatio
const available = Decimal . max (
0 ,
availableVaultBalance . toFixed ( bank . mintDecimals )
)
const feesEarned = toUiDecimals (
bank . collectedFeesNative ,
bank . mintDecimals
)
2023-01-03 01:20:34 -08:00
2023-03-18 04:21:48 -07:00
return (
< TrBody
className = "default-transition md:hover:cursor-pointer md:hover:bg-th-bkg-2"
key = { bank . name }
onClick = { ( ) = > goToTokenPage ( bank ) }
>
< Td >
< div className = "flex items-center" >
< div className = "mr-2.5 flex flex-shrink-0 items-center" >
{ logoURI ? (
< Image
alt = ""
width = "24"
height = "24"
src = { logoURI }
/ >
) : (
< QuestionMarkCircleIcon className = "h-6 w-6 text-th-fgd-3" / >
) }
< / div >
< p className = "font-body" > { bank . name } < / p >
2023-01-03 00:33:30 -08:00
< / div >
2023-03-18 04:21:48 -07:00
< / Td >
< Td >
< div className = "flex flex-col text-right" >
< BankAmountWithValue
amount = { deposits . toFixed ( 4 ) }
bank = { bank }
fixDecimals = { false }
stacked
2023-01-24 02:42:26 -08:00
/ >
2023-03-18 04:21:48 -07:00
< / div >
< / Td >
< Td >
< div className = "flex flex-col text-right" >
< BankAmountWithValue
amount = { borrows . toFixed ( 4 ) }
bank = { bank }
fixDecimals = { false }
stacked
2023-01-24 02:42:26 -08:00
/ >
2023-03-18 04:21:48 -07:00
< / div >
< / Td >
< Td >
< div className = "flex flex-col text-right" >
< BankAmountWithValue
amount = { available }
bank = { bank }
fixDecimals = { false }
stacked
/ >
< / div >
< / Td >
< Td >
< div className = "flex flex-col text-right" >
< BankAmountWithValue
amount = { feesEarned }
bank = { bank }
fixDecimals = { false }
stacked
/ >
< / div >
< / Td >
< Td >
< div className = "flex justify-end space-x-1.5" >
< p className = "text-th-up" >
< FormatNumericValue
value = { bank . getDepositRateUi ( ) }
decimals = { 2 }
/ >
%
< / p >
< span className = "text-th-fgd-4" > | < / span >
< p className = "text-th-down" >
< FormatNumericValue
value = { bank . getBorrowRateUi ( ) }
decimals = { 2 }
/ >
%
< / p >
< / div >
< / Td >
< Td >
< div className = "flex flex-col text-right" >
< p >
{ bank . uiDeposits ( ) > 0
? (
( bank . uiBorrows ( ) / bank . uiDeposits ( ) ) *
100
) . toFixed ( 1 )
: '0.0' }
%
< / p >
< / div >
< / Td >
< Td >
< div className = "flex justify-end space-x-1.5 text-right" >
< p > { bank . initAssetWeight . toFixed ( 2 ) } < / p >
< span className = "text-th-fgd-4" > | < / span >
< p > { bank . initLiabWeight . toFixed ( 2 ) } < / p >
< / div >
< / Td >
< Td >
< div className = "flex justify-end" >
< ChevronRightIcon className = "h-5 w-5 text-th-fgd-3" / >
< / div >
< / Td >
< / TrBody >
)
} ) }
< / tbody >
< / Table >
< / div >
2023-01-03 01:20:34 -08:00
) : (
2023-03-18 04:21:48 -07:00
< div className = "border-b border-th-bkg-3" >
2023-01-29 20:13:38 -08:00
{ banks . map ( ( b ) = > {
const bank = b . bank
2023-01-03 01:20:34 -08:00
let logoURI
if ( mangoTokens ? . length ) {
logoURI = mangoTokens . find (
( t ) = > t . address === bank . mint . toString ( )
) ? . logoURI
}
2023-01-08 16:49:42 -08:00
const deposits = bank . uiDeposits ( )
const borrows = bank . uiBorrows ( )
2023-02-16 02:56:05 -08:00
const availableVaultBalance =
group . getTokenVaultBalanceByMintUi ( bank . mint ) -
deposits * bank . minVaultToDepositsRatio
const available = Decimal . max (
0 ,
availableVaultBalance . toFixed ( bank . mintDecimals )
)
2023-03-18 04:21:48 -07:00
const feesEarned = toUiDecimals (
bank . collectedFeesNative ,
bank . mintDecimals
)
2023-01-03 01:20:34 -08:00
return (
2023-03-18 04:21:48 -07:00
< >
< button
key = { bank . name }
className = "w-full border-t border-th-bkg-3 px-6 py-4 text-left first:border-t-0"
onClick = { ( ) = > handleShowTokenDetails ( bank ) }
>
< div className = "flex items-center justify-between" >
< div className = "flex items-center" >
< div className = "mr-2.5 flex flex-shrink-0 items-center" >
{ logoURI ? (
< Image alt = "" width = "24" height = "24" src = { logoURI } / >
) : (
< QuestionMarkCircleIcon className = "h-7 w-7 text-th-fgd-3" / >
) }
< / div >
< p className = "text-th-fgd-1" > { bank . name } < / p >
2023-01-03 01:20:34 -08:00
< / div >
2023-03-18 04:21:48 -07:00
< ChevronDownIcon
className = { ` ${
showTokenDetails === bank . name
? 'rotate-180'
: 'rotate-360'
} h - 6 w - 6 flex - shrink - 0 text - th - fgd - 3 ` }
/ >
2022-08-23 15:33:09 -07:00
< / div >
2023-03-18 04:21:48 -07:00
< / button >
< Transition
appear = { true }
show = { showTokenDetails === bank . name }
as = { Fragment }
enter = "transition ease-in duration-200"
enterFrom = "opacity-0"
enterTo = "opacity-100"
leave = "transition ease-out"
leaveFrom = "opacity-100"
leaveTo = "opacity-0"
>
< div className = "mx-6 grid grid-cols-2 gap-4 border-t border-th-bkg-3 pb-4 pt-4" >
< div className = "col-span-1" >
< p className = "mb-0.5 text-xs" > { t ( 'total-deposits' ) } < / p >
2023-01-28 17:13:36 -08:00
< BankAmountWithValue
2023-01-24 02:42:26 -08:00
amount = { deposits . toFixed ( 4 ) }
2023-01-28 17:13:36 -08:00
bank = { bank }
fixDecimals = { false }
2023-01-08 19:38:09 -08:00
/ >
2023-01-03 00:33:30 -08:00
< / div >
2023-03-18 04:21:48 -07:00
< div className = "col-span-1" >
< p className = "mb-0.5 text-xs" > { t ( 'total-borrows' ) } < / p >
2023-01-28 17:13:36 -08:00
< BankAmountWithValue
2023-01-24 02:42:26 -08:00
amount = { borrows . toFixed ( 4 ) }
2023-01-28 17:13:36 -08:00
bank = { bank }
fixDecimals = { false }
2023-01-08 19:38:09 -08:00
/ >
2023-01-03 01:20:34 -08:00
< / div >
2023-03-18 04:21:48 -07:00
< div className = "col-span-1" >
< Tooltip content = "The amount available to borrow" >
< p className = "tooltip-underline text-xs" >
{ t ( 'available' ) }
< / p >
< / Tooltip >
< BankAmountWithValue
amount = { available }
bank = { bank }
fixDecimals = { false }
2023-01-03 01:20:34 -08:00
/ >
2023-03-18 04:21:48 -07:00
< / div >
2023-01-03 01:20:34 -08:00
< div className = "col-span-1" >
2023-03-18 04:21:48 -07:00
< Tooltip content = "Fees collected for loan originations" >
< p className = "tooltip-underline text-xs" > { t ( 'fees' ) } < / p >
< / Tooltip >
< BankAmountWithValue
amount = { feesEarned }
bank = { bank }
fixDecimals = { false }
/ >
< / div >
< div className = "col-span-1" >
< p className = "text-xs" > { t ( 'rates' ) } < / p >
2023-01-03 01:20:34 -08:00
< p className = "space-x-2" >
< span className = "font-mono text-th-up" >
2023-01-24 02:42:26 -08:00
< FormatNumericValue
value = { bank . getDepositRateUi ( ) }
decimals = { 2 }
/ >
%
2023-01-03 01:20:34 -08:00
< / span >
< span className = "font-normal text-th-fgd-4" > | < / span >
< span className = "font-mono text-th-down" >
2023-01-24 02:42:26 -08:00
< FormatNumericValue
value = { bank . getBorrowRateUi ( ) }
decimals = { 2 }
/ >
%
2023-01-03 01:20:34 -08:00
< / span >
< / p >
< / div >
< div className = "col-span-1" >
2023-03-18 04:21:48 -07:00
< p className = "text-xs" > { t ( 'utilization' ) } < / p >
2023-01-03 01:20:34 -08:00
< p className = "font-mono text-th-fgd-1" >
{ bank . uiDeposits ( ) > 0
2023-01-24 02:42:26 -08:00
? (
( bank . uiBorrows ( ) / bank . uiDeposits ( ) ) *
100
) . toFixed ( 1 )
2023-01-03 01:20:34 -08:00
: '0.0' }
%
< / p >
< / div >
< div className = "col-span-1" >
2023-01-08 17:31:34 -08:00
< Tooltip content = { t ( 'asset-liability-weight-desc' ) } >
< p className = "tooltip-underline text-xs text-th-fgd-3" >
{ t ( 'asset-liability-weight' ) }
< / p >
< / Tooltip >
< div className = "flex space-x-1.5 text-right font-mono" >
< p className = "text-th-fgd-1" >
{ bank . initAssetWeight . toFixed ( 2 ) }
< / p >
< span className = "text-th-fgd-4" > | < / span >
< p className = "text-th-fgd-1" >
{ bank . initLiabWeight . toFixed ( 2 ) }
< / p >
< / div >
2023-01-03 01:20:34 -08:00
< / div >
< div className = "col-span-1" >
< LinkButton
className = "flex items-center"
onClick = { ( ) = > goToTokenPage ( bank ) }
>
{ t ( 'token:token-details' ) }
< ChevronRightIcon className = "ml-2 h-5 w-5" / >
< / LinkButton >
< / div >
< / div >
< / Transition >
2023-03-18 04:21:48 -07:00
< / >
2023-01-03 01:20:34 -08:00
)
} ) }
2022-08-23 15:33:09 -07:00
< / div >
) }
< / ContentBox >
2023-02-16 02:56:05 -08:00
) : null
2022-08-23 15:33:09 -07:00
}
2022-10-11 04:59:01 -07:00
export default TokenStats