token table overview updates
This commit is contained in:
parent
bedc864717
commit
b1ef1563fa
|
@ -1,15 +1,15 @@
|
|||
import Change from '@components/shared/Change'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import TokenLogo from '@components/shared/TokenLogo'
|
||||
import useListedMarketsWithMarketData, {
|
||||
SerumMarketWithMarketData,
|
||||
} from 'hooks/useListedMarketsWithMarketData'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useMemo } from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { goToTokenPage } from '@components/stats/tokens/TokenOverviewTable'
|
||||
import {
|
||||
ArrowDownTrayIcon,
|
||||
BoltIcon,
|
||||
ChevronRightIcon,
|
||||
FaceFrownIcon,
|
||||
|
@ -25,6 +25,13 @@ import mangoStore from '@store/mangoStore'
|
|||
import { goToPerpMarketDetails } from '@components/stats/perps/PerpMarketDetailsTable'
|
||||
import MarketLogos from '@components/trade/MarketLogos'
|
||||
import { TOKEN_REDUCE_ONLY_OPTIONS } from 'utils/constants'
|
||||
import TableTokenName from '@components/shared/TableTokenName'
|
||||
import { IconButton } from '@components/shared/Button'
|
||||
import DepositWithdrawModal from '@components/modals/DepositWithdrawModal'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import CreateAccountModal from '@components/modals/CreateAccountModal'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
export type BankWithMarketData = {
|
||||
|
@ -39,6 +46,8 @@ const RecentGainersLosers = () => {
|
|||
const { t } = useTranslation(['common', 'explore', 'trade'])
|
||||
const router = useRouter()
|
||||
const { group } = useMangoGroup()
|
||||
const { mangoAccountAddress } = useMangoAccount()
|
||||
const { connected } = useWallet()
|
||||
const { banks } = useBanks()
|
||||
const {
|
||||
serumMarketsWithData,
|
||||
|
@ -46,6 +55,8 @@ const RecentGainersLosers = () => {
|
|||
isLoading: loadingSerumMarkets,
|
||||
} = useListedMarketsWithMarketData()
|
||||
const groupLoaded = mangoStore((s) => s.groupLoaded)
|
||||
const [showDepositModal, setShowDepositModal] = useState('')
|
||||
const [showCreateAccountModal, setShowCreateAccountModal] = useState(false)
|
||||
|
||||
const banksWithMarketData = useMemo(() => {
|
||||
if (!banks.length || !group || !serumMarketsWithData.length) return []
|
||||
|
@ -134,6 +145,14 @@ const RecentGainersLosers = () => {
|
|||
return [gainers, losers]
|
||||
}, [banksWithMarketData, perpMarketsWithData])
|
||||
|
||||
const handleDepositModal = (token: string) => {
|
||||
if (mangoAccountAddress) {
|
||||
setShowDepositModal(token)
|
||||
} else {
|
||||
setShowCreateAccountModal(true)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="grid grid-cols-12 gap-4 px-4 md:px-6">
|
||||
|
@ -152,37 +171,36 @@ const RecentGainersLosers = () => {
|
|||
{groupLoaded ? (
|
||||
<div className="border-t border-th-bkg-3">
|
||||
{newlyListed.map((token) => {
|
||||
const mintInfo = newlyListedMintInfo.find(
|
||||
(info) => info.tokenIndex === token.tokenIndex,
|
||||
)
|
||||
let timeSinceListing = ''
|
||||
if (mintInfo) {
|
||||
timeSinceListing = dayjs().to(
|
||||
mintInfo.registrationTime.toNumber() * 1000,
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className="default-transition flex h-16 cursor-pointer items-center justify-between border-b border-th-bkg-3 px-4 md:hover:bg-th-bkg-2"
|
||||
key={token.tokenIndex}
|
||||
onClick={() =>
|
||||
goToTokenPage(token.name.split(' ')[0], router)
|
||||
}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<TokenLogo bank={token} showRewardsLogo />
|
||||
<p className="ml-3 font-body text-th-fgd-2">
|
||||
{token.name}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="mr-3">
|
||||
<span className="text-th-fgd-3">
|
||||
{timeSinceListing}
|
||||
</span>
|
||||
<div className="relative" key={token.tokenIndex}>
|
||||
<div
|
||||
className="default-transition flex h-16 cursor-pointer items-center justify-between border-b border-th-bkg-3 px-4 md:hover:bg-th-bkg-2"
|
||||
onClick={() =>
|
||||
goToTokenPage(token.name.split(' ')[0], router)
|
||||
}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<TableTokenName
|
||||
bank={token}
|
||||
symbol={token.name}
|
||||
showLeverage
|
||||
hideReduceDesc
|
||||
/>
|
||||
</div>
|
||||
<ChevronRightIcon className="h-5 w-5 text-th-fgd-3" />
|
||||
</div>
|
||||
{connected ? (
|
||||
<div className="absolute right-12 top-4">
|
||||
<Tooltip content={`${t('deposit')} ${token.name}`}>
|
||||
<IconButton
|
||||
onClick={() => handleDepositModal(token.name)}
|
||||
size="small"
|
||||
>
|
||||
<ArrowDownTrayIcon className="h-4 w-4" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
|
@ -219,18 +237,23 @@ const RecentGainersLosers = () => {
|
|||
}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{bank ? (
|
||||
<div className="mr-3">
|
||||
<TokenLogo bank={bank} showRewardsLogo />
|
||||
</div>
|
||||
) : (
|
||||
{bank ? (
|
||||
<div className="mr-3">
|
||||
<TableTokenName
|
||||
bank={bank}
|
||||
symbol={bank.name}
|
||||
showLeverage
|
||||
hideReduceDesc
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center">
|
||||
<MarketLogos market={gainer?.market} size="large" />
|
||||
)}
|
||||
<p className="font-body text-th-fgd-2">
|
||||
{bank?.name || gainer?.market?.name}
|
||||
</p>
|
||||
</div>
|
||||
<p className="font-body text-th-fgd-2">
|
||||
{gainer?.market?.name}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center">
|
||||
<div className="mr-3 flex flex-col items-end">
|
||||
<span className="font-mono">
|
||||
|
@ -282,16 +305,23 @@ const RecentGainersLosers = () => {
|
|||
}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{bank ? (
|
||||
<TokenLogo bank={bank} showRewardsLogo />
|
||||
) : (
|
||||
<MarketLogos market={loser?.market} />
|
||||
)}
|
||||
<p className="ml-3 font-body text-th-fgd-2">
|
||||
{bank?.name || loser?.market?.name}
|
||||
</p>
|
||||
</div>
|
||||
{bank ? (
|
||||
<div className="mr-3">
|
||||
<TableTokenName
|
||||
bank={bank}
|
||||
symbol={bank.name}
|
||||
showLeverage
|
||||
hideReduceDesc
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center">
|
||||
<MarketLogos market={loser?.market} size="large" />
|
||||
<p className="font-body text-th-fgd-2">
|
||||
{loser?.market?.name}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center">
|
||||
<div className="mr-3 flex flex-col items-end">
|
||||
<span className="font-mono">
|
||||
|
@ -316,6 +346,20 @@ const RecentGainersLosers = () => {
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
{showDepositModal ? (
|
||||
<DepositWithdrawModal
|
||||
action="deposit"
|
||||
isOpen={!!showDepositModal}
|
||||
onClose={() => setShowDepositModal('')}
|
||||
token={showDepositModal}
|
||||
/>
|
||||
) : null}
|
||||
{showCreateAccountModal ? (
|
||||
<CreateAccountModal
|
||||
isOpen={showCreateAccountModal}
|
||||
onClose={() => setShowCreateAccountModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,8 @@ import useBanks from 'hooks/useBanks'
|
|||
import SheenLoader from '@components/shared/SheenLoader'
|
||||
import { useViewport } from 'hooks/useViewport'
|
||||
import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||
import { TOKEN_WATCHLIST_KEY } from 'utils/constants'
|
||||
import { TOKEN_REDUCE_ONLY_OPTIONS, TOKEN_WATCHLIST_KEY } from 'utils/constants'
|
||||
import { DEFAULT_WATCHLIST } from './WatchlistButton'
|
||||
|
||||
export type BankWithMarketData = {
|
||||
bank: Bank
|
||||
|
@ -61,14 +62,31 @@ const sortTokens = (
|
|||
return tokens.sort((a: BankWithMarketData, b: BankWithMarketData) => {
|
||||
const aInWatchlist = watchlist.includes(a.bank.tokenIndex)
|
||||
const bInWatchlist = watchlist.includes(b.bank.tokenIndex)
|
||||
const aIsReduce = a.bank.reduceOnly === TOKEN_REDUCE_ONLY_OPTIONS.ENABLED
|
||||
const bIsReduce = b.bank.reduceOnly === TOKEN_REDUCE_ONLY_OPTIONS.ENABLED
|
||||
const aIsNoBorrow =
|
||||
a.bank.reduceOnly === TOKEN_REDUCE_ONLY_OPTIONS.NO_BORROWS
|
||||
const bIsNoBorrow =
|
||||
b.bank.reduceOnly === TOKEN_REDUCE_ONLY_OPTIONS.NO_BORROWS
|
||||
|
||||
// Prioritize tokens in the watchlist
|
||||
// prioritize tokens in the watchlist
|
||||
if (aInWatchlist && !bInWatchlist) {
|
||||
return -1 // a should come before b
|
||||
} else if (!aInWatchlist && bInWatchlist) {
|
||||
return 1 // b should come before a
|
||||
}
|
||||
|
||||
if (!aIsReduce && bIsReduce) {
|
||||
return -1 // a should come before b
|
||||
} else if (aIsReduce && !bIsReduce) {
|
||||
return 1 // b should come before a
|
||||
}
|
||||
|
||||
if (!aIsNoBorrow && bIsNoBorrow) {
|
||||
return -1 // a should come before b
|
||||
} else if (aIsNoBorrow && !bIsNoBorrow) {
|
||||
return 1 // b should come before a
|
||||
}
|
||||
let aValue: number | undefined
|
||||
let bValue: number | undefined
|
||||
if (sortByKey === 'change_24h') {
|
||||
|
@ -94,7 +112,10 @@ const sortTokens = (
|
|||
}
|
||||
|
||||
const Spot = () => {
|
||||
const [watchlist] = useLocalStorageState(TOKEN_WATCHLIST_KEY, [])
|
||||
const [watchlist] = useLocalStorageState(
|
||||
TOKEN_WATCHLIST_KEY,
|
||||
DEFAULT_WATCHLIST,
|
||||
)
|
||||
const { t } = useTranslation(['common', 'explore', 'trade'])
|
||||
const { group } = useMangoGroup()
|
||||
const { banks } = useBanks()
|
||||
|
|
|
@ -4,11 +4,9 @@ import Change from '@components/shared/Change'
|
|||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import TokenLogo from '@components/shared/TokenLogo'
|
||||
import { goToTokenPage } from '@components/stats/tokens/TokenOverviewTable'
|
||||
import Decimal from 'decimal.js'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { numberCompacter } from 'utils/numbers'
|
||||
import { floorToDecimal, numberCompacter } from 'utils/numbers'
|
||||
import { BankWithMarketData } from './Spot'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
import SimpleAreaChart from '@components/shared/SimpleAreaChart'
|
||||
|
@ -18,10 +16,10 @@ import TokenReduceOnlyDesc from '@components/shared/TokenReduceOnlyDesc'
|
|||
import CollateralWeightDisplay from '@components/shared/CollateralWeightDisplay'
|
||||
import WatchlistButton from './WatchlistButton'
|
||||
import TableRatesDisplay from '@components/shared/TableRatesDisplay'
|
||||
import { LeverageMaxDisplay } from './SpotTable'
|
||||
|
||||
const SpotCards = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
||||
const { t } = useTranslation(['common', 'explore', 'trade'])
|
||||
const { group } = useMangoGroup()
|
||||
const { theme } = useThemeWrapper()
|
||||
const router = useRouter()
|
||||
return (
|
||||
|
@ -29,14 +27,6 @@ const SpotCards = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
{tokens.map((token) => {
|
||||
const { bank } = token
|
||||
|
||||
const availableVaultBalance = group
|
||||
? group.getTokenVaultBalanceByMintUi(bank.mint) -
|
||||
bank.uiDeposits() * bank.minVaultToDepositsRatio
|
||||
: 0
|
||||
const available = Decimal.max(
|
||||
0,
|
||||
availableVaultBalance.toFixed(bank.mintDecimals),
|
||||
).mul(bank.uiPrice)
|
||||
const depositRate = bank.getDepositRateUi()
|
||||
const borrowRate = bank.getBorrowRateUi()
|
||||
const chartData = token?.market?.priceHistory?.length
|
||||
|
@ -49,6 +39,10 @@ const SpotCards = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
|
||||
const change = token.market?.rollingChange || 0
|
||||
|
||||
const weight = bank.scaledInitAssetWeight(bank.price)
|
||||
const leverageFactor = 1 / (1 - weight.toNumber())
|
||||
const leverageMax = floorToDecimal(leverageFactor, 1).toNumber()
|
||||
|
||||
return (
|
||||
<div
|
||||
className="col-span-12 rounded-lg border border-th-bkg-3 p-6 md:col-span-6 xl:col-span-4 2xl:col-span-3"
|
||||
|
@ -114,15 +108,8 @@ const SpotCards = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<Tooltip
|
||||
content={t('tooltip-available', { token: bank.name })}
|
||||
placement="top-start"
|
||||
>
|
||||
<p className="tooltip-underline mb-1">{t('available')}</p>
|
||||
</Tooltip>
|
||||
<span className="font-mono text-th-fgd-2">
|
||||
<FormatNumericValue value={available} isUsd />
|
||||
</span>
|
||||
<p className="mb-1">{t('trade:max-leverage')}</p>
|
||||
<LeverageMaxDisplay leverageMax={leverageMax} />
|
||||
</div>
|
||||
<div>
|
||||
<Tooltip
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
TrHead,
|
||||
} from '@components/shared/TableElements'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import { numberCompacter } from 'utils/numbers'
|
||||
import { floorToDecimal, numberCompacter } from 'utils/numbers'
|
||||
import SimpleAreaChart from '@components/shared/SimpleAreaChart'
|
||||
import { Disclosure, Transition } from '@headlessui/react'
|
||||
import { ChevronDownIcon, ChevronRightIcon } from '@heroicons/react/20/solid'
|
||||
|
@ -26,7 +26,6 @@ import TokenLogo from '@components/shared/TokenLogo'
|
|||
import { goToTokenPage } from '@components/stats/tokens/TokenOverviewTable'
|
||||
import { useRouter } from 'next/router'
|
||||
import Decimal from 'decimal.js'
|
||||
import BankAmountWithValue from '@components/shared/BankAmountWithValue'
|
||||
import { BankWithMarketData } from './Spot'
|
||||
import { SerumMarketWithMarketData } from 'hooks/useListedMarketsWithMarketData'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
|
@ -39,6 +38,9 @@ import useLocalStorageState from 'hooks/useLocalStorageState'
|
|||
import { TOKEN_WATCHLIST_KEY } from 'utils/constants'
|
||||
import TableRatesDisplay from '@components/shared/TableRatesDisplay'
|
||||
|
||||
export const GRADIENT_TEXT =
|
||||
'bg-gradient-to-bl from-yellow-500 to-red-500 bg-clip-text text-transparent'
|
||||
|
||||
type TableData = {
|
||||
assetWeight: string
|
||||
available: Decimal
|
||||
|
@ -55,6 +57,7 @@ type TableData = {
|
|||
}[]
|
||||
volume: number
|
||||
isUp: boolean
|
||||
leverageMax: number
|
||||
}
|
||||
|
||||
const SpotTable = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
||||
|
@ -91,6 +94,7 @@ const SpotTable = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
let depositRate = 0
|
||||
let borrowRate = 0
|
||||
let assetWeight = '0'
|
||||
let leverageMax = 0
|
||||
|
||||
if (baseBank) {
|
||||
availableVaultBalance = group
|
||||
|
@ -107,6 +111,10 @@ const SpotTable = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
assetWeight = baseBank
|
||||
.scaledInitAssetWeight(baseBank.price)
|
||||
.toFixed(2)
|
||||
|
||||
const weight = baseBank.scaledInitAssetWeight(baseBank.price)
|
||||
const leverageFactor = 1 / (1 - weight.toNumber())
|
||||
leverageMax = floorToDecimal(leverageFactor, 1).toNumber()
|
||||
}
|
||||
|
||||
const isUp =
|
||||
|
@ -126,6 +134,7 @@ const SpotTable = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
tokenName,
|
||||
volume,
|
||||
isUp,
|
||||
leverageMax,
|
||||
}
|
||||
formatted.push(data)
|
||||
}
|
||||
|
@ -188,15 +197,12 @@ const SpotTable = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
</Th>
|
||||
<Th>
|
||||
<div className="flex justify-end">
|
||||
<Tooltip content={t('tooltip-available', { token: '' })}>
|
||||
<SortableColumnHeader
|
||||
sortKey="availableValue"
|
||||
sort={() => requestSort('availableValue')}
|
||||
sortConfig={sortConfig}
|
||||
title={t('available')}
|
||||
titleClass="tooltip-underline"
|
||||
/>
|
||||
</Tooltip>
|
||||
<SortableColumnHeader
|
||||
sortKey="leverageMax"
|
||||
sort={() => requestSort('leverageMax')}
|
||||
sortConfig={sortConfig}
|
||||
title={t('trade:max-leverage')}
|
||||
/>
|
||||
</div>
|
||||
</Th>
|
||||
<Th>
|
||||
|
@ -246,7 +252,6 @@ const SpotTable = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
})
|
||||
.map((data) => {
|
||||
const {
|
||||
available,
|
||||
baseBank,
|
||||
borrowRate,
|
||||
change,
|
||||
|
@ -257,6 +262,7 @@ const SpotTable = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
tokenName,
|
||||
volume,
|
||||
isUp,
|
||||
leverageMax,
|
||||
} = data
|
||||
|
||||
if (!baseBank) return null
|
||||
|
@ -272,7 +278,7 @@ const SpotTable = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
</td>
|
||||
</tr>
|
||||
<TrBody
|
||||
className="default-transition border-t-0 md:hover:cursor-pointer md:hover:bg-th-bkg-2"
|
||||
className="default-transition h-16 border-t-0 md:hover:cursor-pointer md:hover:bg-th-bkg-2"
|
||||
onClick={() =>
|
||||
goToTokenPage(tokenName.split(' ')[0], router)
|
||||
}
|
||||
|
@ -352,12 +358,7 @@ const SpotTable = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
</Td>
|
||||
<Td>
|
||||
<div className="flex flex-col text-right">
|
||||
<BankAmountWithValue
|
||||
amount={available}
|
||||
bank={baseBank}
|
||||
fixDecimals={false}
|
||||
stacked
|
||||
/>
|
||||
<LeverageMaxDisplay leverageMax={leverageMax} />
|
||||
</div>
|
||||
</Td>
|
||||
<Td className="font-mono">
|
||||
|
@ -417,7 +418,6 @@ const MobileSpotItem = ({ data }: { data: TableData }) => {
|
|||
const router = useRouter()
|
||||
|
||||
const {
|
||||
available,
|
||||
baseBank,
|
||||
borrowRate,
|
||||
change,
|
||||
|
@ -428,6 +428,7 @@ const MobileSpotItem = ({ data }: { data: TableData }) => {
|
|||
tokenName,
|
||||
volume,
|
||||
isUp,
|
||||
leverageMax,
|
||||
} = data
|
||||
|
||||
return (
|
||||
|
@ -521,12 +522,10 @@ const MobileSpotItem = ({ data }: { data: TableData }) => {
|
|||
</p>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<p className="text-xs text-th-fgd-3">{t('available')}</p>
|
||||
<BankAmountWithValue
|
||||
amount={available}
|
||||
bank={baseBank}
|
||||
fixDecimals={false}
|
||||
/>
|
||||
<p className="text-xs text-th-fgd-3">
|
||||
{t('trade:max-leverage')}
|
||||
</p>
|
||||
<LeverageMaxDisplay leverageMax={leverageMax} />
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<p className="text-xs text-th-fgd-3">
|
||||
|
@ -566,3 +565,24 @@ const MobileSpotItem = ({ data }: { data: TableData }) => {
|
|||
</Disclosure>
|
||||
)
|
||||
}
|
||||
|
||||
export const LeverageMaxDisplay = ({
|
||||
leverageMax,
|
||||
}: {
|
||||
leverageMax: number | undefined
|
||||
}) => {
|
||||
return (
|
||||
<span className="font-mono">
|
||||
{leverageMax && leverageMax !== Infinity ? (
|
||||
<span className={`${leverageMax >= 5 ? GRADIENT_TEXT : ''}`}>
|
||||
{leverageMax < 2 && leverageMax > 1
|
||||
? leverageMax.toFixed(1)
|
||||
: leverageMax.toFixed()}
|
||||
x
|
||||
</span>
|
||||
) : (
|
||||
'–'
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ import { TOKEN_WATCHLIST_KEY } from 'utils/constants'
|
|||
import PinFill from '@components/icons/PinFill'
|
||||
import PinOutline from '@components/icons/PinOutline'
|
||||
|
||||
export const DEFAULT_WATCHLIST = [4, 0]
|
||||
|
||||
const WatchlistButton = ({
|
||||
tokenIndex,
|
||||
className,
|
||||
|
@ -12,7 +14,7 @@ const WatchlistButton = ({
|
|||
}) => {
|
||||
const [watchlist, setWatchlist] = useLocalStorageState(
|
||||
TOKEN_WATCHLIST_KEY,
|
||||
[],
|
||||
DEFAULT_WATCHLIST,
|
||||
)
|
||||
|
||||
const toggleWatchlist = (tokenIndex: number) => {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Bank } from '@blockworks-foundation/mango-v4'
|
|||
import TokenLogo from './TokenLogo'
|
||||
import TokenReduceOnlyDesc from './TokenReduceOnlyDesc'
|
||||
import { useVaultLimits } from '@components/swap/useVaultLimits'
|
||||
import { ExclamationTriangleIcon } from '@heroicons/react/20/solid'
|
||||
import { Battery100Icon } from '@heroicons/react/20/solid'
|
||||
import Tooltip from './Tooltip'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
|
@ -12,10 +12,12 @@ const TableTokenName = ({
|
|||
bank,
|
||||
symbol,
|
||||
showLeverage,
|
||||
hideReduceDesc,
|
||||
}: {
|
||||
bank: Bank
|
||||
symbol: string
|
||||
showLeverage?: boolean
|
||||
hideReduceDesc?: boolean
|
||||
}) => {
|
||||
const { t } = useTranslation(['common', 'trade'])
|
||||
const { vaultFull } = useVaultLimits(bank)
|
||||
|
@ -31,8 +33,8 @@ const TableTokenName = ({
|
|||
<div>
|
||||
<div className="flex items-center">
|
||||
<p className="font-body leading-none text-th-fgd-2">{symbol}</p>
|
||||
{showLeverage && leverageMax > 1 && leverageMax < Infinity ? (
|
||||
<div className="ml-1">
|
||||
{showLeverage && leverageMax < Infinity ? (
|
||||
<div className="ml-1.5">
|
||||
<Tooltip content={t('trade:max-leverage')}>
|
||||
<LeverageBadge leverage={leverageMax} />
|
||||
</Tooltip>
|
||||
|
@ -40,11 +42,11 @@ const TableTokenName = ({
|
|||
) : null}
|
||||
{vaultFull ? (
|
||||
<Tooltip content={t('warning-deposits-full', { token: bank.name })}>
|
||||
<ExclamationTriangleIcon className="ml-1 h-4 w-4 text-th-warning" />
|
||||
<Battery100Icon className="ml-1.5 h-5 w-5 text-th-warning" />
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</div>
|
||||
<TokenReduceOnlyDesc bank={bank} />
|
||||
{hideReduceDesc ? null : <TokenReduceOnlyDesc bank={bank} />}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -25,6 +25,8 @@ import { useSortableData } from 'hooks/useSortableData'
|
|||
import TableTokenName from '@components/shared/TableTokenName'
|
||||
import CollateralWeightDisplay from '@components/shared/CollateralWeightDisplay'
|
||||
import OracleProvider from '@components/shared/OracleProvider'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
import { LeverageMaxDisplay } from '@components/explore/SpotTable'
|
||||
|
||||
const TokenDetailsTable = () => {
|
||||
const { t } = useTranslation([
|
||||
|
@ -56,6 +58,9 @@ const TokenDetailsTable = () => {
|
|||
const [oracleProvider, oracleLinkPath] = getOracleProvider(bank)
|
||||
const symbol = bank.name
|
||||
const collateralFeeRate = bank.collateralFeePerDay * 100
|
||||
const weight = bank.scaledInitAssetWeight(bank.price)
|
||||
const leverageFactor = 1 / (1 - weight.toNumber())
|
||||
const leverageMax = floorToDecimal(leverageFactor, 1).toNumber()
|
||||
|
||||
const data = {
|
||||
bank,
|
||||
|
@ -69,6 +74,7 @@ const TokenDetailsTable = () => {
|
|||
oracleProvider,
|
||||
symbol,
|
||||
collateralFeeRate,
|
||||
leverageMax,
|
||||
}
|
||||
formatted.push(data)
|
||||
}
|
||||
|
@ -111,6 +117,16 @@ const TokenDetailsTable = () => {
|
|||
</Tooltip>
|
||||
</div>
|
||||
</Th>
|
||||
<Th>
|
||||
<div className="flex justify-end">
|
||||
<SortableColumnHeader
|
||||
sortKey="leverageMax"
|
||||
sort={() => requestSort('leverageMax')}
|
||||
sortConfig={sortConfig}
|
||||
title={t('trade:max-leverage')}
|
||||
/>
|
||||
</div>
|
||||
</Th>
|
||||
<Th>
|
||||
<div className="flex justify-end">
|
||||
<Tooltip content={t('tooltip-borrow-fee')}>
|
||||
|
@ -204,6 +220,7 @@ const TokenDetailsTable = () => {
|
|||
loanOriginationFee,
|
||||
symbol,
|
||||
collateralFeeRate,
|
||||
leverageMax,
|
||||
} = data
|
||||
|
||||
return (
|
||||
|
@ -226,6 +243,11 @@ const TokenDetailsTable = () => {
|
|||
<p>{initLiabWeight.toFixed(2)}x</p>
|
||||
</div>
|
||||
</Td>
|
||||
<Td>
|
||||
<div className="flex flex-col text-right">
|
||||
<LeverageMaxDisplay leverageMax={leverageMax} />
|
||||
</div>
|
||||
</Td>
|
||||
<Td>
|
||||
<p className="text-right">
|
||||
{loanOriginationFee.toFixed(2)}%
|
||||
|
@ -268,6 +290,7 @@ const TokenDetailsTable = () => {
|
|||
liquidationFee,
|
||||
loanOriginationFee,
|
||||
collateralFeeRate,
|
||||
leverageMax,
|
||||
} = data
|
||||
return (
|
||||
<Disclosure key={bank.name}>
|
||||
|
@ -313,6 +336,12 @@ const TokenDetailsTable = () => {
|
|||
<span>{initLiabWeight.toFixed(2)}x</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<p className="text-xs text-th-fgd-3">
|
||||
{t('trade:max-leverage')}
|
||||
</p>
|
||||
<LeverageMaxDisplay leverageMax={leverageMax} />
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<Tooltip
|
||||
content={t('tooltip-borrow-fee')}
|
||||
|
|
|
@ -41,6 +41,7 @@ import { TOKEN_REDUCE_ONLY_OPTIONS } from 'utils/constants'
|
|||
import { isBankVisibleForUser } from 'utils/bank'
|
||||
import Decimal from 'decimal.js'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import { GRADIENT_TEXT } from '@components/explore/SpotTable'
|
||||
|
||||
type Currencies = {
|
||||
[key: string]: string
|
||||
|
@ -526,8 +527,15 @@ export default MarketSelectDropdown
|
|||
|
||||
export const LeverageBadge = ({ leverage }: { leverage: number }) => {
|
||||
return (
|
||||
<div className="rounded bg-th-bkg-3 px-1 py-0.5 font-mono text-xxs leading-none text-th-fgd-2">
|
||||
<span>{leverage < 2 ? leverage.toFixed(1) : leverage.toFixed()}x</span>
|
||||
<div
|
||||
className={`rounded bg-th-bkg-3 px-1 py-0.5 font-mono text-xs leading-none`}
|
||||
>
|
||||
<span className={leverage >= 5 ? GRADIENT_TEXT : 'text-th-fgd-3'}>
|
||||
{leverage > 1 && leverage < 2
|
||||
? leverage.toFixed(1)
|
||||
: leverage.toFixed()}
|
||||
x
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue