show all token rates
This commit is contained in:
parent
c73b5346a3
commit
b1dd5fc7f4
|
@ -0,0 +1,79 @@
|
|||
import Image from 'next/image'
|
||||
import { formatTokenSymbol } from 'utils/tokens'
|
||||
import useBankRates from 'hooks/useBankRates'
|
||||
import useLeverageMax from 'hooks/useLeverageMax'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import SheenLoader from './shared/SheenLoader'
|
||||
|
||||
const HeroTokenButton = ({
|
||||
onClick,
|
||||
tokenName,
|
||||
}: {
|
||||
tokenName: string
|
||||
onClick: () => void
|
||||
}) => {
|
||||
const leverage = useLeverageMax(tokenName)
|
||||
const groupLoaded = mangoStore((s) => s.groupLoaded)
|
||||
|
||||
const { stakeBankDepositRate, financialMetrics } = useBankRates(
|
||||
tokenName,
|
||||
leverage,
|
||||
)
|
||||
|
||||
const { financialMetrics: estimatedNetAPYFor1xLev } = useBankRates(
|
||||
tokenName,
|
||||
1,
|
||||
)
|
||||
|
||||
const APY_Daily_Compound =
|
||||
Math.pow(1 + Number(stakeBankDepositRate) / 365, 365) - 1
|
||||
const UiRate =
|
||||
tokenName === 'USDC'
|
||||
? APY_Daily_Compound * 100
|
||||
: Math.max(estimatedNetAPYFor1xLev.APY, financialMetrics.APY)
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`inner-shadow-bottom default-transition w-full rounded-xl border border-th-bkg-3 bg-th-bkg-1 p-6 text-th-fgd-1 focus:outline-none focus-visible:border-th-fgd-4 md:hover:bg-th-bkg-2 md:hover:focus-visible:border-th-fgd-4`}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div>
|
||||
<div className="flex flex-col items-center">
|
||||
<div
|
||||
className={`inner-shadow-bottom-sm mb-2 flex h-14 w-14 items-center justify-center rounded-full border border-th-bkg-2 bg-gradient-to-b from-th-bkg-1 to-th-bkg-2`}
|
||||
>
|
||||
<Image
|
||||
src={`/icons/${tokenName.toLowerCase()}.svg`}
|
||||
width={32}
|
||||
height={32}
|
||||
alt="Select a token"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col items-center">
|
||||
<p className={`text-th-fgd-1`}>{formatTokenSymbol(tokenName)}</p>
|
||||
<span className={`text-xl font-bold`}>
|
||||
{!groupLoaded ? (
|
||||
<SheenLoader>
|
||||
<div className={`h-6 w-10 bg-th-bkg-2`} />
|
||||
</SheenLoader>
|
||||
) : !UiRate || isNaN(UiRate) ? (
|
||||
<span className="text-base font-normal text-th-fgd-4">
|
||||
Rate Unavailable
|
||||
</span>
|
||||
) : (
|
||||
`${UiRate.toFixed(2)}%`
|
||||
)}
|
||||
</span>
|
||||
{groupLoaded ? (
|
||||
<span className="text-sm text-th-fgd-4">
|
||||
{tokenName === 'USDC' ? 'APY' : 'Max APY'}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default HeroTokenButton
|
|
@ -17,7 +17,7 @@ const HydrateStore = () => {
|
|||
const { mangoAccountPk } = useMangoAccount()
|
||||
const selectedToken = mangoStore((s) => s.selectedToken)
|
||||
const clientContext =
|
||||
getStakableTokensDataForTokenName(selectedToken).clientContext
|
||||
getStakableTokensDataForTokenName(selectedToken)?.clientContext
|
||||
|
||||
const connection = mangoStore((s) => s.connection)
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import TokenSelect from './TokenSelect'
|
|||
import Label from './forms/Label'
|
||||
import usePositions from 'hooks/usePositions'
|
||||
import { IconButton } from './shared/Button'
|
||||
import HeroTokenButton from './HeroTokenButton'
|
||||
|
||||
const set = mangoStore.getState().set
|
||||
|
||||
|
@ -48,8 +49,13 @@ const Stake = () => {
|
|||
state.selectedToken = positions[0].bank.name
|
||||
})
|
||||
}
|
||||
if (tab === 'Add' && selectedToken) {
|
||||
set((state) => {
|
||||
state.selectedToken = ''
|
||||
})
|
||||
}
|
||||
},
|
||||
[hasPosition, positions],
|
||||
[hasPosition, positions, selectedToken],
|
||||
)
|
||||
|
||||
const selectableTokens = useMemo(() => {
|
||||
|
@ -143,58 +149,79 @@ const Stake = () => {
|
|||
/>
|
||||
</div>
|
||||
{selectableTokens.length ? (
|
||||
<>
|
||||
<div className="pb-6">
|
||||
<Label text="Token" />
|
||||
<TokenButton
|
||||
onClick={() => setShowTokenSelect(true)}
|
||||
tokenName={selectedToken}
|
||||
/>
|
||||
</div>
|
||||
{selectedToken == 'USDC' ? (
|
||||
<>
|
||||
{activeFormTab === 'Add' ? (
|
||||
<DespositForm
|
||||
token="USDC"
|
||||
clientContext={
|
||||
getStakableTokensDataForTokenName('USDC')
|
||||
.clientContext
|
||||
!selectedToken ? (
|
||||
<>
|
||||
<h2 className="mb-3 text-center text-lg font-normal">
|
||||
Select token to Boost!
|
||||
</h2>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{selectableTokens.map((token) => (
|
||||
<HeroTokenButton
|
||||
key={token}
|
||||
onClick={() =>
|
||||
set((state) => {
|
||||
state.selectedToken = token
|
||||
})
|
||||
}
|
||||
tokenName={token}
|
||||
/>
|
||||
) : null}
|
||||
{activeFormTab === 'Remove' ? (
|
||||
<UnstakeForm
|
||||
token="USDC"
|
||||
clientContext={
|
||||
getStakableTokensDataForTokenName('USDC')
|
||||
.clientContext
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{activeFormTab === 'Add' ? (
|
||||
<StakeForm
|
||||
token={selectedToken}
|
||||
clientContext={
|
||||
getStakableTokensDataForTokenName(selectedToken)
|
||||
.clientContext
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{activeFormTab === 'Remove' ? (
|
||||
<UnstakeForm
|
||||
token={selectedToken}
|
||||
clientContext={
|
||||
getStakableTokensDataForTokenName(selectedToken)
|
||||
.clientContext
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="pb-6">
|
||||
<Label text="Token" />
|
||||
<TokenButton
|
||||
onClick={() => setShowTokenSelect(true)}
|
||||
tokenName={selectedToken}
|
||||
/>
|
||||
</div>
|
||||
{selectedToken == 'USDC' ? (
|
||||
<>
|
||||
{activeFormTab === 'Add' ? (
|
||||
<DespositForm
|
||||
token="USDC"
|
||||
clientContext={
|
||||
getStakableTokensDataForTokenName('USDC')
|
||||
.clientContext
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{activeFormTab === 'Remove' ? (
|
||||
<UnstakeForm
|
||||
token="USDC"
|
||||
clientContext={
|
||||
getStakableTokensDataForTokenName('USDC')
|
||||
.clientContext
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{activeFormTab === 'Add' ? (
|
||||
<StakeForm
|
||||
token={selectedToken}
|
||||
clientContext={
|
||||
getStakableTokensDataForTokenName(selectedToken)
|
||||
?.clientContext
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{activeFormTab === 'Remove' ? (
|
||||
<UnstakeForm
|
||||
token={selectedToken}
|
||||
clientContext={
|
||||
getStakableTokensDataForTokenName(selectedToken)
|
||||
?.clientContext
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
) : (
|
||||
<div className="p-10">
|
||||
<p className="text-center text-th-fgd-4">
|
||||
|
@ -205,7 +232,7 @@ const Stake = () => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{activeFormTab === 'Add' ? (
|
||||
{activeFormTab === 'Add' && selectedToken ? (
|
||||
<div className="fixed bottom-0 left-0 z-20 w-full lg:bottom-8 lg:left-8 lg:w-auto">
|
||||
{isDesktop ? (
|
||||
<a
|
||||
|
|
|
@ -35,7 +35,7 @@ const TokenButton = ({
|
|||
|
||||
return (
|
||||
<button
|
||||
className={`inner-shadow-bottom-sm w-full rounded-xl border border-th-bkg-3 bg-th-bkg-1 p-3 text-th-fgd-1 focus:outline-none focus-visible:border-th-fgd-4 md:hover:border-th-bkg-4 md:hover:focus-visible:border-th-fgd-4`}
|
||||
className={`inner-shadow-bottom-sm default-transition w-full rounded-xl border border-th-bkg-3 bg-th-bkg-1 p-3 text-th-fgd-1 focus:outline-none focus-visible:border-th-fgd-4 md:hover:bg-th-bkg-2 md:hover:focus-visible:border-th-fgd-4`}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
|
@ -51,20 +51,30 @@ const TokenButton = ({
|
|||
/>
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<p className={`text-lg font-bold text-th-fgd-1`}>
|
||||
<p className={`mb-0.5 text-th-fgd-1`}>
|
||||
{formatTokenSymbol(tokenName)}
|
||||
</p>
|
||||
<span className={`font-medium text-th-fgd-4`}>
|
||||
<span className={`text-lg font-bold leading-none text-th-fgd-1`}>
|
||||
{!groupLoaded ? (
|
||||
<SheenLoader>
|
||||
<div className={`h-5 w-10 bg-th-bkg-2`} />
|
||||
</SheenLoader>
|
||||
) : !UiRate || isNaN(UiRate) ? (
|
||||
'Rate Unavailable'
|
||||
<span className="text-base font-normal text-th-fgd-4">
|
||||
Rate Unavailable
|
||||
</span>
|
||||
) : tokenName === 'USDC' ? (
|
||||
`${UiRate.toFixed(2)}% APY`
|
||||
<>
|
||||
{`${UiRate.toFixed(2)}%`}{' '}
|
||||
<span className="text-sm font-normal text-th-fgd-4">APY</span>
|
||||
</>
|
||||
) : (
|
||||
`Up to ${UiRate.toFixed(2)}% APY`
|
||||
<>
|
||||
{`${UiRate.toFixed(2)}%`}{' '}
|
||||
<span className="text-sm font-normal text-th-fgd-4">
|
||||
Max APY
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -70,10 +70,12 @@ const TokenSelect = ({
|
|||
/>
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<p className={`text-sm font-bold text-th-fgd-1 sm:text-lg`}>
|
||||
<p className={`text-sm text-th-fgd-1 lg:text-base`}>
|
||||
{formatTokenSymbol(tokenName)}
|
||||
</p>
|
||||
<span className={`text-sm text-th-fgd-4`}>
|
||||
<span
|
||||
className={`text-sm font-bold leading-none text-th-fgd-1 sm:text-lg`}
|
||||
>
|
||||
{!groupLoaded ? (
|
||||
<SheenLoader>
|
||||
<div className={`h-5 w-10 bg-th-bkg-2`} />
|
||||
|
@ -81,9 +83,17 @@ const TokenSelect = ({
|
|||
) : !UiRate || isNaN(UiRate) ? (
|
||||
'Rate Unavailable'
|
||||
) : tokenName === 'USDC' ? (
|
||||
`${UiRate.toFixed(2)}% APY`
|
||||
<>
|
||||
{`${UiRate.toFixed(2)}%`}{' '}
|
||||
<span className="text-sm font-normal text-th-fgd-4">APY</span>
|
||||
</>
|
||||
) : (
|
||||
`Up to ${UiRate.toFixed(2)}% APY`
|
||||
<>
|
||||
{`${UiRate.toFixed(2)}%`}{' '}
|
||||
<span className="text-sm font-normal text-th-fgd-4">
|
||||
Max APY
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -43,7 +43,6 @@ import {
|
|||
MAX_PRIORITY_FEE_KEYS,
|
||||
PAGINATION_PAGE_LENGTH,
|
||||
RPC_PROVIDER_KEY,
|
||||
STAKEABLE_TOKENS,
|
||||
SWAP_MARGIN_KEY,
|
||||
} from '../utils/constants'
|
||||
import {
|
||||
|
@ -332,7 +331,7 @@ const mangoStore = create<MangoStore>()(
|
|||
return {
|
||||
// leverage stake
|
||||
activeTab: 'Boost!',
|
||||
selectedToken: STAKEABLE_TOKENS[0],
|
||||
selectedToken: '',
|
||||
estimatedMaxAPY: {
|
||||
current: 0,
|
||||
},
|
||||
|
|
|
@ -386,27 +386,27 @@ table p {
|
|||
/* shadows */
|
||||
|
||||
.inner-shadow-top {
|
||||
@apply shadow-[inset_0_4px_0px_rgba(0,0,0,0.15)];
|
||||
@apply shadow-[inset_0_4px_0px_var(--bkg-3)];
|
||||
}
|
||||
|
||||
.inner-shadow-bottom {
|
||||
@apply shadow-[inset_0_-4px_0px_rgba(0,0,0,0.15)];
|
||||
@apply shadow-[inset_0_-4px_0px_var(--bkg-3)];
|
||||
}
|
||||
|
||||
.inner-shadow-top-sm {
|
||||
@apply shadow-[inset_0_2px_0px_rgba(0,0,0,0.15)];
|
||||
@apply shadow-[inset_0_2px_0px_var(--bkg-3)];
|
||||
}
|
||||
|
||||
.inner-shadow-bottom-sm {
|
||||
@apply shadow-[inset_0_-2px_0px_rgba(0,0,0,0.15)];
|
||||
@apply shadow-[inset_0_-2px_0px_var(--bkg-3)];
|
||||
}
|
||||
|
||||
.inner-shadow-top-xs {
|
||||
@apply shadow-[inset_0_1px_0px_rgba(0,0,0,0.15)];
|
||||
@apply shadow-[inset_0_1px_0px_var(--bkg-3)];
|
||||
}
|
||||
|
||||
.inner-shadow-bottom-xs {
|
||||
@apply shadow-[inset_0_-1px_0px_rgba(0,0,0,0.15)];
|
||||
@apply shadow-[inset_0_-1px_0px_var(--bkg-3)];
|
||||
}
|
||||
|
||||
.text-shadow {
|
||||
|
@ -457,4 +457,4 @@ table p {
|
|||
|
||||
.rotate-bg-5x {
|
||||
animation: rotate-bg 3s linear infinite;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue