add functional funding rate + selector (#729)

* add functional funding rate + selector

* Edit perps position (#728)
This commit is contained in:
Bob van der Helm 2024-01-12 12:10:26 +01:00 committed by GitHub
parent 647a287a6b
commit 7629e2442f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 117 additions and 41 deletions

View File

@ -0,0 +1,77 @@
import { useMemo, useState } from 'react'
import { FormattedNumber } from 'components/FormattedNumber'
import { ChevronDown } from 'components/Icons'
import Loading from 'components/Loading'
import { Tooltip } from 'components/Tooltip'
import { BN_ZERO } from 'constants/math'
import usePerpsMarket from 'hooks/perps/usePerpsMarket'
import useToggle from 'hooks/useToggle'
type Interval = '1H' | '1D' | '1W' | '1M' | '1Y'
enum Intervals {
'1H' = 365 * 24,
'1D' = 365,
'1W' = 52,
'1M' = 12,
'1Y' = 1,
}
export default function FundingRate() {
const { data: market, isLoading } = usePerpsMarket()
const [interval, setInterval] = useState<Interval>('1H')
const [show, toggleShow] = useToggle(false)
const fundingRate = useMemo(() => {
return market?.fundingRate.div(Intervals[interval]) ?? BN_ZERO
}, [interval, market?.fundingRate])
if (isLoading) return <Loading className='w-14 h-4' />
if (!market) return '-'
return (
<div className='flex gap-1'>
<FormattedNumber
className='text-sm inline'
amount={fundingRate.toNumber()}
options={{ minDecimals: 6, maxDecimals: 6, suffix: '%' }}
/>
<Tooltip
content={
<div>
{Object.keys(Intervals)
.filter((key) => isNaN(Number(key)))
.map((key) => (
<button
key={key}
onClick={() => {
setInterval(key as Interval)
toggleShow(false)
}}
className='w-full text-left px-4 py-2 flex gap-2 items-center hover:bg-white/5 [&:not(:last-child)]:border-b border-white/10'
>
{key}
</button>
))}
</div>
}
type='info'
placement='bottom'
contentClassName='!bg-white/10 border border-white/20 backdrop-blur-xl !p-0'
interactive
hideArrow
visible={show}
onClickOutside={() => toggleShow(false)}
>
<button
onClick={() => toggleShow()}
className='flex gap-1 bg-white/10 rounded-sm items-center text-[10px] px-1.5 py-0.5'
>
{interval}
<ChevronDown className='h-2 w-2' />
</button>
</Tooltip>
</div>
)
}

View File

@ -0,0 +1,27 @@
import React from 'react'
import AssetSymbol from 'components/Asset/AssetSymbol'
import { FormattedNumber } from 'components/FormattedNumber'
import Loading from 'components/Loading'
import usePerpsMarket from 'hooks/perps/usePerpsMarket'
interface InterestItemProps {
type: 'long' | 'short'
}
export default function InterestItem(props: InterestItemProps) {
const { data: market, isLoading } = usePerpsMarket()
if (isLoading) return <Loading />
if (!market) return null
return (
<div className='flex gap-1 items-center'>
<FormattedNumber
className='text-sm inline'
amount={market.openInterest[props.type].toNumber()}
options={{ decimals: market.asset.decimals }}
/>
<AssetSymbol symbol={market.asset.symbol} />
</div>
)
}

View File

@ -1,11 +1,11 @@
import React, { useMemo } from 'react'
import AssetSymbol from 'components/Asset/AssetSymbol'
import Card from 'components/Card'
import DisplayCurrency from 'components/DisplayCurrency'
import Divider from 'components/Divider'
import { FormattedNumber } from 'components/FormattedNumber'
import Loading from 'components/Loading'
import FundingRate from 'components/Perps/PerpsInfo/FundingRate'
import InterestItem from 'components/Perps/PerpsInfo/InterestItem'
import Text from 'components/Text'
import usePerpsMarket from 'hooks/perps/usePerpsMarket'
import usePrice from 'hooks/usePrice'
@ -25,28 +25,14 @@ export function PerpsInfo() {
<InfoItem
key='openInterestLong'
label='Open Interest (L)'
item={<InterestItem market={market} type='long' />}
item={<InterestItem type='long' />}
/>,
<InfoItem
key='openInterestShort'
label='Open Interest (S)'
item={<InterestItem market={market} type='short' />}
/>,
<InfoItem
key='fundingRate'
label='Funding rate'
item={
market ? (
<FormattedNumber
className='text-sm inline'
amount={market.fundingRate.toNumber()}
options={{ minDecimals: 6, maxDecimals: 6, suffix: '%' }}
/>
) : (
<Loading />
)
}
item={<InterestItem type='short' />}
/>,
<InfoItem key='fundingRate' label='Funding rate' item={<FundingRate />} />,
]
}, [assetPrice, market])
@ -81,22 +67,3 @@ function InfoItem(props: InfoItemProps) {
</div>
)
}
interface InterestItemProps {
market: PerpsMarket | null
type: 'long' | 'short'
}
function InterestItem(props: InterestItemProps) {
if (!props.market) return <Loading />
return (
<div className='flex gap-1 items-center'>
<FormattedNumber
className='text-sm inline'
amount={props.market.openInterest[props.type].toNumber()}
options={{ decimals: props.market.asset.decimals }}
/>
<AssetSymbol symbol={props.market.asset.symbol} />
</div>
)
}

View File

@ -11,15 +11,20 @@ export default function usePerpsMarket() {
const { perpsAsset } = usePerpsAsset()
const clients = useClients()
return useSWR(clients && perpsAsset && `chains/${chainConfig.id}/perps/${perpsAsset.denom}`, () =>
getPerpsMarket(clients!, perpsAsset!),
return useSWR(
clients && perpsAsset && `chains/${chainConfig.id}/perps/${perpsAsset.denom}`,
() => getPerpsMarket(clients!, perpsAsset!),
{
refreshInterval: 1000,
dedupingInterval: 1000,
},
)
}
async function getPerpsMarket(clients: ContractClients, asset: Asset) {
const denomState = await clients.perps.perpDenomState({ denom: asset.denom })
return {
fundingRate: BN(denomState.rate.abs),
fundingRate: BN(denomState.rate as any),
asset: asset,
openInterest: {
long: BN_ZERO,