Merge pull request #83 from blockworks-foundation/swap-reduce-only
handle swap reduce only
This commit is contained in:
commit
6ec8f9d262
|
@ -4,11 +4,13 @@ import FormatNumericValue from './FormatNumericValue'
|
|||
|
||||
const Change = ({
|
||||
change,
|
||||
decimals,
|
||||
prefix,
|
||||
size,
|
||||
suffix,
|
||||
}: {
|
||||
change: number | typeof NaN
|
||||
decimals?: number
|
||||
prefix?: string
|
||||
size?: 'small'
|
||||
suffix?: string
|
||||
|
@ -44,7 +46,7 @@ const Change = ({
|
|||
{prefix ? prefix : ''}
|
||||
<FormatNumericValue
|
||||
value={isNaN(change) ? '0.00' : Math.abs(change)}
|
||||
decimals={2}
|
||||
decimals={decimals ? decimals : 2}
|
||||
/>
|
||||
{suffix ? suffix : ''}
|
||||
</p>
|
||||
|
|
|
@ -45,6 +45,7 @@ interface DetailedAreaChartProps {
|
|||
tickFormat?: (x: number) => string
|
||||
title?: string
|
||||
xKey: string
|
||||
yDecimals?: number
|
||||
yKey: string
|
||||
}
|
||||
|
||||
|
@ -72,6 +73,7 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
tickFormat,
|
||||
title,
|
||||
xKey,
|
||||
yDecimals,
|
||||
yKey,
|
||||
}) => {
|
||||
const { t } = useTranslation('common')
|
||||
|
@ -92,22 +94,43 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
setMouseData(null)
|
||||
}
|
||||
|
||||
const calculateChartChange = () => {
|
||||
if (data.length) {
|
||||
if (mouseData) {
|
||||
const index = data.findIndex((d: any) => d[xKey] === mouseData[xKey])
|
||||
const change = index >= 0 ? data[index][yKey] - data[0][yKey] : 0
|
||||
return isNaN(change) ? 0 : change
|
||||
} else return data[data.length - 1][yKey] - data[0][yKey]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
const flipGradientCoords = useMemo(() => {
|
||||
if (!data.length) return
|
||||
return data[0][yKey] <= 0 && data[data.length - 1][yKey] <= 0
|
||||
}, [data])
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data.length) return []
|
||||
if (daysToShow !== '30') {
|
||||
const seconds = Number(daysToShow) * 86400
|
||||
const filtered = data.filter((d: any) => {
|
||||
const dataTime = new Date(d[xKey]).getTime() / 1000
|
||||
const now = new Date().getTime() / 1000
|
||||
const limit = now - seconds
|
||||
return dataTime >= limit
|
||||
})
|
||||
return filtered
|
||||
}
|
||||
return data
|
||||
}, [data, daysToShow])
|
||||
|
||||
const calculateChartChange = () => {
|
||||
if (filteredData.length) {
|
||||
if (mouseData) {
|
||||
const index = filteredData.findIndex(
|
||||
(d: any) => d[xKey] === mouseData[xKey]
|
||||
)
|
||||
const change =
|
||||
index >= 0 ? filteredData[index][yKey] - filteredData[0][yKey] : 0
|
||||
return isNaN(change) ? 0 : change
|
||||
} else
|
||||
return (
|
||||
filteredData[filteredData.length - 1][yKey] - filteredData[0][yKey]
|
||||
)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
return (
|
||||
<FadeInFadeOut show={true}>
|
||||
<ContentBox hideBorder hidePadding>
|
||||
|
@ -119,7 +142,7 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
} w-full rounded-lg bg-th-bkg-2`}
|
||||
/>
|
||||
</SheenLoader>
|
||||
) : data.length ? (
|
||||
) : filteredData.length ? (
|
||||
<div className="relative">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex flex-col md:flex-row md:items-start md:space-x-6">
|
||||
|
@ -157,7 +180,8 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
numbers={`${
|
||||
mouseData[yKey] < 0 ? '-' : ''
|
||||
}${prefix}${formatNumericValue(
|
||||
Math.abs(mouseData[yKey])
|
||||
Math.abs(mouseData[yKey]),
|
||||
yDecimals
|
||||
)}${suffix}`}
|
||||
/>
|
||||
) : (
|
||||
|
@ -166,6 +190,7 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
{prefix}
|
||||
<FormatNumericValue
|
||||
value={Math.abs(mouseData[yKey])}
|
||||
decimals={yDecimals}
|
||||
/>
|
||||
{suffix}
|
||||
</span>
|
||||
|
@ -174,6 +199,7 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
<span className="ml-3">
|
||||
<Change
|
||||
change={calculateChartChange()}
|
||||
decimals={yDecimals}
|
||||
prefix={prefix}
|
||||
suffix={suffix}
|
||||
/>
|
||||
|
@ -203,17 +229,25 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
width={small ? 17 : 30}
|
||||
play
|
||||
numbers={`${
|
||||
data[data.length - 1][yKey] < 0 ? '-' : ''
|
||||
filteredData[filteredData.length - 1][yKey] < 0
|
||||
? '-'
|
||||
: ''
|
||||
}${prefix}${formatNumericValue(
|
||||
Math.abs(data[data.length - 1][yKey])
|
||||
Math.abs(
|
||||
filteredData[filteredData.length - 1][yKey]
|
||||
),
|
||||
yDecimals
|
||||
)}${suffix}`}
|
||||
/>
|
||||
) : (
|
||||
<span>
|
||||
{data[data.length - 1][yKey] < 0 ? '-' : ''}
|
||||
{filteredData[filteredData.length - 1][yKey] < 0
|
||||
? '-'
|
||||
: ''}
|
||||
{prefix}
|
||||
<FormatNumericValue
|
||||
value={Math.abs(data[data.length - 1][yKey])}
|
||||
decimals={yDecimals}
|
||||
/>
|
||||
{suffix}
|
||||
</span>
|
||||
|
@ -222,6 +256,7 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
<span className="ml-3">
|
||||
<Change
|
||||
change={calculateChartChange()}
|
||||
decimals={yDecimals}
|
||||
prefix={prefix}
|
||||
suffix={suffix}
|
||||
/>
|
||||
|
@ -233,9 +268,9 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
small ? 'text-xs' : 'text-sm'
|
||||
} text-th-fgd-4`}
|
||||
>
|
||||
{dayjs(data[data.length - 1][xKey]).format(
|
||||
'DD MMM YY, h:mma'
|
||||
)}
|
||||
{dayjs(
|
||||
filteredData[filteredData.length - 1][xKey]
|
||||
).format('DD MMM YY, h:mma')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
@ -258,7 +293,7 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
<div className="-mx-6 mt-6 h-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<AreaChart
|
||||
data={data}
|
||||
data={filteredData}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
|
|
|
@ -68,42 +68,12 @@ const MangoPerpStatsCharts = () => {
|
|||
return values.reverse()
|
||||
}, [perpStats])
|
||||
|
||||
const filteredOiValues = useMemo(() => {
|
||||
if (!totalOpenInterestValues.length) return []
|
||||
if (oiDaysToShow !== '30') {
|
||||
const seconds = Number(oiDaysToShow) * 86400
|
||||
const data = totalOpenInterestValues.filter((d: OiValueItem) => {
|
||||
const dataTime = new Date(d.date).getTime() / 1000
|
||||
const now = new Date().getTime() / 1000
|
||||
const limit = now - seconds
|
||||
return dataTime >= limit
|
||||
})
|
||||
return data
|
||||
}
|
||||
return totalOpenInterestValues
|
||||
}, [totalOpenInterestValues, oiDaysToShow])
|
||||
|
||||
const filteredFeesValues = useMemo(() => {
|
||||
if (!totalFeeValues.length) return []
|
||||
if (feesDaysToShow !== '30') {
|
||||
const seconds = Number(feesDaysToShow) * 86400
|
||||
const data = totalFeeValues.filter((d: FeeValueItem) => {
|
||||
const dataTime = new Date(d.date).getTime() / 1000
|
||||
const now = new Date().getTime() / 1000
|
||||
const limit = now - seconds
|
||||
return dataTime >= limit
|
||||
})
|
||||
return data
|
||||
}
|
||||
return totalFeeValues
|
||||
}, [totalFeeValues, feesDaysToShow])
|
||||
|
||||
return (
|
||||
<>
|
||||
{totalFeeValues.length ? (
|
||||
{totalOpenInterestValues.length ? (
|
||||
<div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1">
|
||||
<DetailedAreaChart
|
||||
data={filteredOiValues}
|
||||
data={totalOpenInterestValues}
|
||||
daysToShow={oiDaysToShow}
|
||||
setDaysToShow={setOiDaysToShow}
|
||||
heightClass="h-64"
|
||||
|
@ -117,10 +87,10 @@ const MangoPerpStatsCharts = () => {
|
|||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{totalOpenInterestValues.length ? (
|
||||
{totalFeeValues.length ? (
|
||||
<div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1 md:border-l md:pl-6">
|
||||
<DetailedAreaChart
|
||||
data={filteredFeesValues}
|
||||
data={totalFeeValues}
|
||||
daysToShow={feesDaysToShow}
|
||||
setDaysToShow={setFeesDaysToShow}
|
||||
heightClass="h-64"
|
||||
|
|
|
@ -1,33 +1,58 @@
|
|||
import { IconButton } from '@components/shared/Button'
|
||||
import SheenLoader from '@components/shared/SheenLoader'
|
||||
import { ChevronLeftIcon } from '@heroicons/react/20/solid'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import dayjs from 'dayjs'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useMemo } from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { formatYAxis } from 'utils/formatting'
|
||||
import { formatNumericValue } from 'utils/numbers'
|
||||
import { usePerpFundingRate } from '@components/trade/PerpFundingRate'
|
||||
const DetailedAreaChart = dynamic(
|
||||
() => import('@components/shared/DetailedAreaChart'),
|
||||
{ ssr: false }
|
||||
)
|
||||
|
||||
const PerpMarketDetails = ({
|
||||
perpMarket,
|
||||
perpMarketName,
|
||||
setShowPerpDetails,
|
||||
}: {
|
||||
perpMarket: string
|
||||
perpMarketName: string
|
||||
setShowPerpDetails: (x: string) => void
|
||||
}) => {
|
||||
const { t } = useTranslation(['common', 'trade'])
|
||||
const perpMarkets = mangoStore((s) => s.perpMarkets)
|
||||
const perpStats = mangoStore((s) => s.perpStats.data)
|
||||
const loadingPerpStats = mangoStore((s) => s.perpStats.loading)
|
||||
const [priceDaysToShow, setPriceDaysToShow] = useState('30')
|
||||
const [oiDaysToShow, setOiDaysToShow] = useState('30')
|
||||
const [hourlyFundingeDaysToShow, setHourlyFundingDaysToShow] = useState('30')
|
||||
const [instantFundingDaysToShow, setInstantFundingDaysToShow] = useState('30')
|
||||
const rate = usePerpFundingRate()
|
||||
|
||||
const marketStats = useMemo(() => {
|
||||
if (!perpStats) return []
|
||||
return perpStats.filter((stat) => stat.perp_market === perpMarket).reverse()
|
||||
const perpMarket = useMemo(() => {
|
||||
return perpMarkets.find((m) => (m.name = perpMarketName))
|
||||
}, [perpMarkets, perpMarketName])
|
||||
|
||||
const [marketStats, lastStat] = useMemo(() => {
|
||||
if (!perpStats) return [[], undefined]
|
||||
const stats = perpStats
|
||||
.filter((stat) => stat.perp_market === perpMarketName)
|
||||
.reverse()
|
||||
return [stats, stats[stats.length - 1]]
|
||||
}, [perpStats])
|
||||
|
||||
const fundingRate = useMemo(() => {
|
||||
if (!lastStat) return 0
|
||||
if (rate?.isSuccess) {
|
||||
const marketRate = rate?.data?.find(
|
||||
(r) => r.market_index === perpMarket?.perpMarketIndex
|
||||
)
|
||||
return marketRate?.funding_rate_hourly
|
||||
}
|
||||
return lastStat.instantaneous_funding_rate
|
||||
}, [rate, lastStat])
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-2">
|
||||
<div className="col-span-2 flex items-center border-b border-th-bkg-3 px-6 py-3">
|
||||
|
@ -38,38 +63,24 @@ const PerpMarketDetails = ({
|
|||
>
|
||||
<ChevronLeftIcon className="h-5 w-5" />
|
||||
</IconButton>
|
||||
<h2 className="text-lg">{`${perpMarket} ${t('stats')}`}</h2>
|
||||
<h2 className="text-lg">{`${perpMarketName} ${t('stats')}`}</h2>
|
||||
</div>
|
||||
{loadingPerpStats ? (
|
||||
<>
|
||||
<div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1">
|
||||
<SheenLoader className="flex flex-1">
|
||||
<div className="h-96 w-full rounded-lg bg-th-bkg-2" />
|
||||
</SheenLoader>
|
||||
</div>
|
||||
<div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1 md:border-l md:pl-6">
|
||||
<SheenLoader className="flex flex-1">
|
||||
<div className="h-96 w-full rounded-lg bg-th-bkg-2" />
|
||||
</SheenLoader>
|
||||
</div>
|
||||
<div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1">
|
||||
<SheenLoader className="flex flex-1">
|
||||
<div className="h-96 w-full rounded-lg bg-th-bkg-2" />
|
||||
</SheenLoader>
|
||||
</div>
|
||||
<div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1 md:border-l md:pl-6">
|
||||
<SheenLoader className="flex flex-1">
|
||||
<div className="h-96 w-full rounded-lg bg-th-bkg-2" />
|
||||
</SheenLoader>
|
||||
</div>
|
||||
</>
|
||||
) : marketStats.length ? (
|
||||
{marketStats.length && lastStat ? (
|
||||
<>
|
||||
<div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1">
|
||||
<DetailedAreaChart
|
||||
data={marketStats}
|
||||
daysToShow={'999'}
|
||||
data={marketStats.concat([
|
||||
{
|
||||
...lastStat,
|
||||
date_hour: dayjs().toISOString(),
|
||||
price: perpMarket?._uiPrice || lastStat.price,
|
||||
},
|
||||
])}
|
||||
daysToShow={priceDaysToShow}
|
||||
setDaysToShow={setPriceDaysToShow}
|
||||
heightClass="h-64"
|
||||
loading={loadingPerpStats}
|
||||
loaderHeightClass="h-[350px]"
|
||||
prefix="$"
|
||||
tickFormat={(x) => formatYAxis(x)}
|
||||
title={t('price')}
|
||||
|
@ -79,10 +90,21 @@ const PerpMarketDetails = ({
|
|||
</div>
|
||||
<div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1 md:border-l md:pl-6">
|
||||
<DetailedAreaChart
|
||||
data={marketStats}
|
||||
daysToShow={'999'}
|
||||
data={marketStats.concat([
|
||||
{
|
||||
...lastStat,
|
||||
date_hour: dayjs().toISOString(),
|
||||
open_interest:
|
||||
perpMarket?.baseLotsToUi(perpMarket.openInterest) ||
|
||||
lastStat.open_interest,
|
||||
},
|
||||
])}
|
||||
daysToShow={oiDaysToShow}
|
||||
setDaysToShow={setOiDaysToShow}
|
||||
heightClass="h-64"
|
||||
tickFormat={(x) => Math.floor(x).toString()}
|
||||
loading={loadingPerpStats}
|
||||
loaderHeightClass="h-[350px]"
|
||||
tickFormat={(x) => formatYAxis(x)}
|
||||
title={t('trade:open-interest')}
|
||||
xKey="date_hour"
|
||||
yKey={'open_interest'}
|
||||
|
@ -91,25 +113,39 @@ const PerpMarketDetails = ({
|
|||
<div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1">
|
||||
<DetailedAreaChart
|
||||
data={marketStats}
|
||||
daysToShow={'999'}
|
||||
daysToShow={hourlyFundingeDaysToShow}
|
||||
setDaysToShow={setHourlyFundingDaysToShow}
|
||||
heightClass="h-64"
|
||||
loading={loadingPerpStats}
|
||||
loaderHeightClass="h-[350px]"
|
||||
suffix="%"
|
||||
tickFormat={(x) => formatNumericValue(x, 4)}
|
||||
title={t('trade:hourly-funding')}
|
||||
xKey="date_hour"
|
||||
yKey={'funding_rate_hourly'}
|
||||
yDecimals={5}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-2 border-b border-th-bkg-3 py-4 px-6 md:col-span-1 md:border-l md:pl-6">
|
||||
<DetailedAreaChart
|
||||
data={marketStats}
|
||||
daysToShow={'999'}
|
||||
data={marketStats.concat([
|
||||
{
|
||||
...lastStat,
|
||||
date_hour: dayjs().toISOString(),
|
||||
instantaneous_funding_rate: fundingRate,
|
||||
},
|
||||
])}
|
||||
daysToShow={instantFundingDaysToShow}
|
||||
setDaysToShow={setInstantFundingDaysToShow}
|
||||
heightClass="h-64"
|
||||
loading={loadingPerpStats}
|
||||
loaderHeightClass="h-[350px]"
|
||||
suffix="%"
|
||||
tickFormat={(x) => formatNumericValue(x, 4)}
|
||||
title={t('trade:instantaneous-funding')}
|
||||
xKey="date_hour"
|
||||
yKey={'instantaneous_funding_rate'}
|
||||
yDecimals={5}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -87,7 +87,7 @@ const PerpMarketsTable = ({
|
|||
: 0
|
||||
|
||||
let fundingRate
|
||||
if (rate.isSuccess && market instanceof PerpMarket) {
|
||||
if (rate.isSuccess) {
|
||||
const marketRate = rate?.data?.find(
|
||||
(r) => r.market_index === market.perpMarketIndex
|
||||
)
|
||||
|
@ -198,6 +198,7 @@ const PerpMarketsTable = ({
|
|||
<MobilePerpMarketItem
|
||||
key={market.publicKey.toString()}
|
||||
market={market}
|
||||
setShowPerpDetails={setShowPerpDetails}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
|
@ -209,7 +210,13 @@ const PerpMarketsTable = ({
|
|||
|
||||
export default PerpMarketsTable
|
||||
|
||||
const MobilePerpMarketItem = ({ market }: { market: PerpMarket }) => {
|
||||
const MobilePerpMarketItem = ({
|
||||
market,
|
||||
setShowPerpDetails,
|
||||
}: {
|
||||
market: PerpMarket
|
||||
setShowPerpDetails: (x: string) => void
|
||||
}) => {
|
||||
const { t } = useTranslation('common')
|
||||
const loadingPerpStats = mangoStore((s) => s.perpStats.loading)
|
||||
const perpStats = mangoStore((s) => s.perpStats.data)
|
||||
|
@ -252,10 +259,9 @@ const MobilePerpMarketItem = ({ market }: { market: PerpMarket }) => {
|
|||
<Change change={change} suffix="%" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{!loadingPerpStats ? (
|
||||
marketStats.length ? (
|
||||
<div className="h-10 w-24">
|
||||
<div className="ml-4 h-10 w-24">
|
||||
<SimpleAreaChart
|
||||
color={change >= 0 ? COLORS.UP[theme] : COLORS.DOWN[theme]}
|
||||
data={marketStats}
|
||||
|
@ -271,6 +277,13 @@ const MobilePerpMarketItem = ({ market }: { market: PerpMarket }) => {
|
|||
<div className="h-10 w-[104px] animate-pulse rounded bg-th-bkg-3" />
|
||||
)}
|
||||
</div>
|
||||
<IconButton
|
||||
onClick={() => setShowPerpDetails(market.name)}
|
||||
size="medium"
|
||||
>
|
||||
<ChevronRightIcon className="h-5 w-5" />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ const PerpStats = () => {
|
|||
<PerpMarketsTable setShowPerpDetails={setShowPerpDetails} />
|
||||
) : (
|
||||
<PerpMarketDetails
|
||||
perpMarket={showPerpDetails}
|
||||
perpMarketName={showPerpDetails}
|
||||
setShowPerpDetails={setShowPerpDetails}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -48,36 +48,6 @@ const TotalDepositBorrowCharts = () => {
|
|||
return values.reverse()
|
||||
}, [tokenStats])
|
||||
|
||||
const filteredBorrowValues = useMemo(() => {
|
||||
if (!totalDepositBorrowValues) return []
|
||||
if (borrowDaysToShow !== '30') {
|
||||
const seconds = Number(borrowDaysToShow) * 86400
|
||||
const data = totalDepositBorrowValues.filter((d) => {
|
||||
const dataTime = new Date(d.date).getTime() / 1000
|
||||
const now = new Date().getTime() / 1000
|
||||
const limit = now - seconds
|
||||
return dataTime >= limit
|
||||
})
|
||||
return data
|
||||
}
|
||||
return totalDepositBorrowValues
|
||||
}, [totalDepositBorrowValues, borrowDaysToShow])
|
||||
|
||||
const filteredDepositValues = useMemo(() => {
|
||||
if (!totalDepositBorrowValues) return []
|
||||
if (depositDaysToShow !== '30') {
|
||||
const seconds = Number(depositDaysToShow) * 86400
|
||||
const data = totalDepositBorrowValues.filter((d) => {
|
||||
const dataTime = new Date(d.date).getTime() / 1000
|
||||
const now = new Date().getTime() / 1000
|
||||
const limit = now - seconds
|
||||
return dataTime >= limit
|
||||
})
|
||||
return data
|
||||
}
|
||||
return totalDepositBorrowValues
|
||||
}, [totalDepositBorrowValues, depositDaysToShow])
|
||||
|
||||
const [currentTotalDepositValue, currentTotalBorrowValue] = useMemo(() => {
|
||||
if (banks.length) {
|
||||
return [
|
||||
|
@ -92,7 +62,7 @@ const TotalDepositBorrowCharts = () => {
|
|||
<>
|
||||
<div className="col-span-2 h-96 border-b border-th-bkg-3 py-4 px-6 md:col-span-1">
|
||||
<DetailedAreaChart
|
||||
data={filteredDepositValues.concat([
|
||||
data={totalDepositBorrowValues.concat([
|
||||
{
|
||||
date: dayjs().toISOString(),
|
||||
depositValue: Math.floor(currentTotalDepositValue),
|
||||
|
@ -113,7 +83,7 @@ const TotalDepositBorrowCharts = () => {
|
|||
</div>
|
||||
<div className="col-span-2 h-96 border-b border-th-bkg-3 py-4 px-6 md:col-span-1 md:border-l md:pl-6">
|
||||
<DetailedAreaChart
|
||||
data={filteredBorrowValues.concat([
|
||||
data={totalDepositBorrowValues.concat([
|
||||
{
|
||||
date: dayjs().toISOString(),
|
||||
borrowValue: Math.floor(currentTotalBorrowValue),
|
||||
|
|
|
@ -63,7 +63,7 @@ const SwapForm = () => {
|
|||
//initial state is undefined null is returned on error
|
||||
const [selectedRoute, setSelectedRoute] = useState<RouteInfo | null>()
|
||||
const [animateSwitchArrow, setAnimateSwitchArrow] = useState(0)
|
||||
const [showTokenSelect, setShowTokenSelect] = useState('')
|
||||
const [showTokenSelect, setShowTokenSelect] = useState(undefined)
|
||||
const [showSettings, setShowSettings] = useState(false)
|
||||
const [showConfirm, setShowConfirm] = useState(false)
|
||||
const { group } = useMangoGroup()
|
||||
|
@ -193,7 +193,7 @@ const SwapForm = () => {
|
|||
s.swap.inputBank = bank
|
||||
})
|
||||
}
|
||||
setShowTokenSelect('')
|
||||
setShowTokenSelect(undefined)
|
||||
}, [])
|
||||
|
||||
const handleTokenOutSelect = useCallback((mintAddress: string) => {
|
||||
|
@ -204,7 +204,7 @@ const SwapForm = () => {
|
|||
s.swap.outputBank = bank
|
||||
})
|
||||
}
|
||||
setShowTokenSelect('')
|
||||
setShowTokenSelect(undefined)
|
||||
}, [])
|
||||
|
||||
const handleSwitchTokens = useCallback(() => {
|
||||
|
@ -299,7 +299,7 @@ const SwapForm = () => {
|
|||
show={!!showTokenSelect}
|
||||
>
|
||||
<SwapFormTokenList
|
||||
onClose={() => setShowTokenSelect('')}
|
||||
onClose={() => setShowTokenSelect(undefined)}
|
||||
onTokenSelect={
|
||||
showTokenSelect === 'input'
|
||||
? handleTokenInSelect
|
||||
|
@ -451,6 +451,26 @@ const SwapForm = () => {
|
|||
{group && inputBank ? (
|
||||
<TokenVaultWarnings bank={inputBank} type="swap" />
|
||||
) : null}
|
||||
{inputBank && inputBank.reduceOnly ? (
|
||||
<div className="pb-4">
|
||||
<InlineNotification
|
||||
type="warning"
|
||||
desc={t('swap:input-reduce-only-warning', {
|
||||
symbol: inputBank.name,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{outputBank && outputBank.reduceOnly ? (
|
||||
<div className="pb-4">
|
||||
<InlineNotification
|
||||
type="warning"
|
||||
desc={t('swap:output-reduce-only-warning', {
|
||||
symbol: outputBank.name,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="space-y-2">
|
||||
<div id="swap-step-four">
|
||||
<HealthImpact maintProjectedHealth={maintProjectedHealth} />
|
||||
|
|
|
@ -47,10 +47,17 @@ const TokenItem = ({
|
|||
token: Token
|
||||
onSubmit: (x: string) => void
|
||||
useMargin: boolean
|
||||
type: string
|
||||
type: 'input' | 'output' | undefined
|
||||
}) => {
|
||||
const { t } = useTranslation('trade')
|
||||
const { address, symbol, logoURI, name } = token
|
||||
|
||||
const bank = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
if (!group) return
|
||||
return group.getFirstBankByMint(new PublicKey(address))
|
||||
}, [address])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button
|
||||
|
@ -64,10 +71,18 @@ const TokenItem = ({
|
|||
<img src={logoURI} width="24" height="24" alt={symbol} />
|
||||
</picture>
|
||||
<div className="ml-2.5">
|
||||
<div className="text-left text-th-fgd-2">{symbol || 'unknown'}</div>
|
||||
<div className="text-left text-xs text-th-fgd-4">
|
||||
<p className="text-left text-th-fgd-2">
|
||||
{symbol || 'unknown'}
|
||||
{bank?.reduceOnly ? (
|
||||
<span className="ml-1.5 text-xxs text-th-warning">
|
||||
{t('reduce-only')}
|
||||
</span>
|
||||
) : null}
|
||||
</p>
|
||||
|
||||
<p className="text-left text-xs text-th-fgd-4">
|
||||
{name || 'unknown'}
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{type === 'input' &&
|
||||
|
@ -103,7 +118,7 @@ const SwapFormTokenList = ({
|
|||
}: {
|
||||
onClose: () => void
|
||||
onTokenSelect: (x: string) => void
|
||||
type: string
|
||||
type: 'input' | 'output' | undefined
|
||||
useMargin: boolean
|
||||
}) => {
|
||||
const { t } = useTranslation(['common', 'swap'])
|
||||
|
|
|
@ -49,7 +49,13 @@ export const getTokenInMax = (
|
|||
mangoAccount.getTokenBalanceUi(inputBank)
|
||||
)
|
||||
|
||||
const maxAmountWithoutMargin = inputTokenBalance.gt(0)
|
||||
const outputTokenBalance = new Decimal(
|
||||
mangoAccount.getTokenBalanceUi(outputBank)
|
||||
)
|
||||
|
||||
const maxAmountWithoutMargin =
|
||||
(inputTokenBalance.gt(0) && !outputBank.reduceOnly) ||
|
||||
(outputBank.reduceOnly && outputTokenBalance.lt(0))
|
||||
? inputTokenBalance
|
||||
: new Decimal(0)
|
||||
|
||||
|
@ -60,7 +66,10 @@ export const getTokenInMax = (
|
|||
)
|
||||
|
||||
const maxUiAmountWithBorrow =
|
||||
rawMaxUiAmountWithBorrow > 0
|
||||
outputBank.reduceOnly &&
|
||||
(outputTokenBalance.gt(0) || outputTokenBalance.eq(0))
|
||||
? new Decimal(0)
|
||||
: rawMaxUiAmountWithBorrow > 0
|
||||
? floorToDecimal(rawMaxUiAmountWithBorrow, inputBank.mintDecimals)
|
||||
: new Decimal(0)
|
||||
|
||||
|
@ -83,10 +92,9 @@ export const getTokenInMax = (
|
|||
maxUiAmountWithBorrow
|
||||
)
|
||||
|
||||
const maxAmountWithBorrow = Decimal.min(
|
||||
maxUiAmountWithBorrow,
|
||||
inputBankVaultBalance
|
||||
)
|
||||
const maxAmountWithBorrow = inputBank.reduceOnly
|
||||
? Decimal.min(maxAmountWithoutMargin, inputBankVaultBalance)
|
||||
: Decimal.min(maxUiAmountWithBorrow, inputBankVaultBalance)
|
||||
|
||||
return {
|
||||
amount: maxAmount,
|
||||
|
|
|
@ -46,20 +46,20 @@ const ChartTabs = ({ token }: { token: string }) => {
|
|||
}, [])
|
||||
}, [tokenStats])
|
||||
|
||||
const filterStats = (daysToShow: string) => {
|
||||
if (!statsHistory.length) return []
|
||||
if (daysToShow !== '30') {
|
||||
const seconds = Number(daysToShow) * 86400
|
||||
const data = statsHistory.filter((d) => {
|
||||
const dataTime = new Date(d.date_hour).getTime() / 1000
|
||||
const now = new Date().getTime() / 1000
|
||||
const limit = now - seconds
|
||||
return dataTime >= limit
|
||||
})
|
||||
return data
|
||||
}
|
||||
return statsHistory
|
||||
}
|
||||
// const filterStats = (daysToShow: string) => {
|
||||
// if (!statsHistory.length) return []
|
||||
// if (daysToShow !== '30') {
|
||||
// const seconds = Number(daysToShow) * 86400
|
||||
// const data = statsHistory.filter((d) => {
|
||||
// const dataTime = new Date(d.date_hour).getTime() / 1000
|
||||
// const now = new Date().getTime() / 1000
|
||||
// const limit = now - seconds
|
||||
// return dataTime >= limit
|
||||
// })
|
||||
// return data
|
||||
// }
|
||||
// return statsHistory
|
||||
// }
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2">
|
||||
|
@ -77,7 +77,7 @@ const ChartTabs = ({ token }: { token: string }) => {
|
|||
<div className="h-96 border-t border-th-bkg-3 px-6 py-6">
|
||||
{activeDepositsTab === 'token:deposits' ? (
|
||||
<DetailedAreaChart
|
||||
data={filterStats(depositDaysToShow)}
|
||||
data={statsHistory}
|
||||
daysToShow={depositDaysToShow}
|
||||
setDaysToShow={setDepositDaysToShow}
|
||||
heightClass="h-64"
|
||||
|
@ -92,7 +92,7 @@ const ChartTabs = ({ token }: { token: string }) => {
|
|||
/>
|
||||
) : (
|
||||
<DetailedAreaChart
|
||||
data={filterStats(depositRateDaysToShow)}
|
||||
data={statsHistory}
|
||||
daysToShow={depositRateDaysToShow}
|
||||
setDaysToShow={setDepositRateDaysToShow}
|
||||
heightClass="h-64"
|
||||
|
@ -125,7 +125,7 @@ const ChartTabs = ({ token }: { token: string }) => {
|
|||
<div className="h-96 border-t border-th-bkg-3 px-6 py-6">
|
||||
{activeBorrowsTab === 'token:borrows' ? (
|
||||
<DetailedAreaChart
|
||||
data={filterStats(borrowDaysToShow)}
|
||||
data={statsHistory}
|
||||
daysToShow={borrowDaysToShow}
|
||||
setDaysToShow={setBorrowDaysToShow}
|
||||
heightClass="h-64"
|
||||
|
@ -140,7 +140,7 @@ const ChartTabs = ({ token }: { token: string }) => {
|
|||
/>
|
||||
) : (
|
||||
<DetailedAreaChart
|
||||
data={filterStats(borrowRateDaysToShow)}
|
||||
data={statsHistory}
|
||||
daysToShow={borrowRateDaysToShow}
|
||||
setDaysToShow={setBorrowRateDaysToShow}
|
||||
heightClass="h-64"
|
||||
|
|
|
@ -561,7 +561,7 @@ const AdvancedTradeForm = () => {
|
|||
checked={tradeForm.reduceOnly}
|
||||
onChange={(e) => handleReduceOnlyChange(e.target.checked)}
|
||||
>
|
||||
Reduce Only
|
||||
{t('trade:reduce-only')}
|
||||
</Checkbox>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
"fees-paid-to": "Fees Paid to {{route}}",
|
||||
"health-impact": "Health Impact",
|
||||
"hide-fees": "Hide Fees",
|
||||
"input-reduce-only-warning": "{{symbol}} is in reduce only mode. You can swap your balance to another token",
|
||||
"insufficient-balance": "Insufficient {{symbol}} Balance",
|
||||
"insufficient-collateral": "Insufficient Collateral",
|
||||
"max-slippage": "Max Slippage",
|
||||
"maximum-cost": "Maximum Cost",
|
||||
"minimum-received": "Minimum Received",
|
||||
"no-history": "No swap history",
|
||||
"output-reduce-only-warning": "{{symbol}} is in reduce only mode. You can swap to close borrows only",
|
||||
"paid": "Paid",
|
||||
"pay": "You Pay",
|
||||
"preset": "Preset",
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
"post": "Post",
|
||||
"price-expect": "The price you receive may be worse than you expect and full execution is not guaranteed. Max slippage is 2.5% for your safety. The part of your position with slippage beyond 2.5% will not be closed.",
|
||||
"quote": "Quote",
|
||||
"reduce-only": "Reduce Only",
|
||||
"sells": "Sells",
|
||||
"settle-funds": "Settle Funds",
|
||||
"settle-funds-error": "Failed to settle funds",
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
"fees-paid-to": "Fees Paid to {{route}}",
|
||||
"health-impact": "Health Impact",
|
||||
"hide-fees": "Hide Fees",
|
||||
"input-reduce-only-warning": "{{symbol}} is in reduce only mode. You can swap your balance to another token",
|
||||
"insufficient-balance": "Insufficient {{symbol}} Balance",
|
||||
"insufficient-collateral": "Insufficient Collateral",
|
||||
"max-slippage": "Max Slippage",
|
||||
"maximum-cost": "Maximum Cost",
|
||||
"minimum-received": "Minimum Received",
|
||||
"no-history": "No swap history",
|
||||
"output-reduce-only-warning": "{{symbol}} is in reduce only mode. You can swap to close borrows only",
|
||||
"paid": "Paid",
|
||||
"pay": "You Pay",
|
||||
"preset": "Preset",
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
"post": "Post",
|
||||
"price-expect": "The price you receive may be worse than you expect and full execution is not guaranteed. Max slippage is 2.5% for your safety. The part of your position with slippage beyond 2.5% will not be closed.",
|
||||
"quote": "Quote",
|
||||
"reduce-only": "Reduce Only",
|
||||
"sells": "Sells",
|
||||
"settle-funds": "Settle Funds",
|
||||
"settle-funds-error": "Failed to settle funds",
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
"fees-paid-to": "Fees Paid to {{route}}",
|
||||
"health-impact": "Health Impact",
|
||||
"hide-fees": "Hide Fees",
|
||||
"input-reduce-only-warning": "{{symbol}} is in reduce only mode. You can swap your balance to another token",
|
||||
"insufficient-balance": "Insufficient {{symbol}} Balance",
|
||||
"insufficient-collateral": "Insufficient Collateral",
|
||||
"max-slippage": "Max Slippage",
|
||||
"maximum-cost": "Maximum Cost",
|
||||
"minimum-received": "Minimum Received",
|
||||
"no-history": "No swap history",
|
||||
"output-reduce-only-warning": "{{symbol}} is in reduce only mode. You can swap to close borrows only",
|
||||
"paid": "Paid",
|
||||
"pay": "You Pay",
|
||||
"preset": "Preset",
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
"post": "Post",
|
||||
"price-expect": "The price you receive may be worse than you expect and full execution is not guaranteed. Max slippage is 2.5% for your safety. The part of your position with slippage beyond 2.5% will not be closed.",
|
||||
"quote": "Quote",
|
||||
"reduce-only": "Reduce Only",
|
||||
"sells": "Sells",
|
||||
"settle-funds": "Settle Funds",
|
||||
"settle-funds-error": "Failed to settle funds",
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
"fees-paid-to": "Fees Paid to {{route}}",
|
||||
"health-impact": "Health Impact",
|
||||
"hide-fees": "Hide Fees",
|
||||
"input-reduce-only-warning": "{{symbol}} is in reduce only mode. You can swap your balance to another token",
|
||||
"insufficient-balance": "Insufficient {{symbol}} Balance",
|
||||
"insufficient-collateral": "Insufficient Collateral",
|
||||
"max-slippage": "Max Slippage",
|
||||
"maximum-cost": "Maximum Cost",
|
||||
"minimum-received": "Minimum Received",
|
||||
"no-history": "No swap history",
|
||||
"output-reduce-only-warning": "{{symbol}} is in reduce only mode. You can swap to close borrows only",
|
||||
"paid": "Paid",
|
||||
"pay": "You Pay",
|
||||
"preset": "Preset",
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
"fees-paid-to": "Fees Paid to {{route}}",
|
||||
"health-impact": "Health Impact",
|
||||
"hide-fees": "Hide Fees",
|
||||
"input-reduce-only-warning": "{{symbol}} is in reduce only mode. You can swap your balance to another token",
|
||||
"insufficient-balance": "Insufficient {{symbol}} Balance",
|
||||
"insufficient-collateral": "Insufficient Collateral",
|
||||
"max-slippage": "Max Slippage",
|
||||
"maximum-cost": "Maximum Cost",
|
||||
"minimum-received": "Minimum Received",
|
||||
"no-history": "No swap history",
|
||||
"output-reduce-only-warning": "{{symbol}} is in reduce only mode. You can swap to close borrows only",
|
||||
"paid": "Paid",
|
||||
"pay": "You Pay",
|
||||
"preset": "Preset",
|
||||
|
|
Loading…
Reference in New Issue