fix position apy
This commit is contained in:
parent
f18757a96c
commit
68f10e23b1
|
@ -11,7 +11,7 @@ const AccountStats = ({ token }: { token: string }) => {
|
||||||
|
|
||||||
const solBank = useMemo(() => {
|
const solBank = useMemo(() => {
|
||||||
return group?.banksMapByName.get('SOL')?.[0]
|
return group?.banksMapByName.get('SOL')?.[0]
|
||||||
}, [group, token])
|
}, [group])
|
||||||
|
|
||||||
const tokenBank = useMemo(() => {
|
const tokenBank = useMemo(() => {
|
||||||
return group?.banksMapByName.get(token)?.[0]
|
return group?.banksMapByName.get(token)?.[0]
|
||||||
|
|
|
@ -7,36 +7,23 @@ import { formatTokenSymbol } from 'utils/tokens'
|
||||||
import mangoStore from '@store/mangoStore'
|
import mangoStore from '@store/mangoStore'
|
||||||
import Switch from './forms/Switch'
|
import Switch from './forms/Switch'
|
||||||
import useLocalStorageState from 'hooks/useLocalStorageState'
|
import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||||
import useStakeRates from 'hooks/useStakeRates'
|
|
||||||
import SheenLoader from './shared/SheenLoader'
|
|
||||||
import useStakeAccounts from 'hooks/useStakeAccounts'
|
import useStakeAccounts from 'hooks/useStakeAccounts'
|
||||||
import FormatNumericValue from './shared/FormatNumericValue'
|
import FormatNumericValue from './shared/FormatNumericValue'
|
||||||
import {
|
import {
|
||||||
Bank,
|
Bank,
|
||||||
Group,
|
|
||||||
MangoAccount,
|
MangoAccount,
|
||||||
toUiDecimalsForQuote,
|
toUiDecimalsForQuote,
|
||||||
} from '@blockworks-foundation/mango-v4'
|
} from '@blockworks-foundation/mango-v4'
|
||||||
|
import useBankRates from 'hooks/useBankRates'
|
||||||
|
|
||||||
const set = mangoStore.getState().set
|
const set = mangoStore.getState().set
|
||||||
|
|
||||||
const BORROW_TOKEN = 'SOL'
|
const BORROW_TOKEN = 'SOL'
|
||||||
|
|
||||||
const getLeverage = (group: Group, mangoAccount: MangoAccount): number => {
|
type Position = {
|
||||||
if (!group || !mangoAccount) return 0
|
borrowBalance: number
|
||||||
const accountValue = toUiDecimalsForQuote(
|
stakeBalance: number
|
||||||
mangoAccount.getEquity(group).toNumber(),
|
bank: Bank
|
||||||
)
|
acct: MangoAccount | undefined
|
||||||
|
|
||||||
const assetsValue = toUiDecimalsForQuote(
|
|
||||||
mangoAccount.getAssetsValue(group).toNumber(),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (isNaN(assetsValue / accountValue)) {
|
|
||||||
return 0
|
|
||||||
} else {
|
|
||||||
return Math.abs(1 - assetsValue / accountValue) + 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getLiquidationRatio = (
|
const getLiquidationRatio = (
|
||||||
|
@ -57,7 +44,6 @@ const Positions = ({
|
||||||
setActiveTab: (tab: string) => void
|
setActiveTab: (tab: string) => void
|
||||||
}) => {
|
}) => {
|
||||||
const { group } = useMangoGroup()
|
const { group } = useMangoGroup()
|
||||||
const { data: stakeRates, isLoading: loadingRates } = useStakeRates()
|
|
||||||
const [showInactivePositions, setShowInactivePositions] =
|
const [showInactivePositions, setShowInactivePositions] =
|
||||||
useLocalStorageState(SHOW_INACTIVE_POSITIONS_KEY, true)
|
useLocalStorageState(SHOW_INACTIVE_POSITIONS_KEY, true)
|
||||||
const { stakeAccounts } = useStakeAccounts()
|
const { stakeAccounts } = useStakeAccounts()
|
||||||
|
@ -100,13 +86,6 @@ const Positions = ({
|
||||||
return positions.filter((pos) => pos.stakeBalance > 0).length
|
return positions.filter((pos) => pos.stakeBalance > 0).length
|
||||||
}, [positions])
|
}, [positions])
|
||||||
|
|
||||||
const handleAddOrManagePosition = (token: string) => {
|
|
||||||
setActiveTab('Stake')
|
|
||||||
set((state) => {
|
|
||||||
state.selectedToken = token
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mb-2 flex items-center justify-between rounded-lg border-2 border-th-fgd-1 bg-th-bkg-1 px-6 py-3.5">
|
<div className="mb-2 flex items-center justify-between rounded-lg border-2 border-th-fgd-1 bg-th-bkg-1 px-6 py-3.5">
|
||||||
|
@ -122,92 +101,14 @@ const Positions = ({
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 gap-2">
|
<div className="grid grid-cols-1 gap-2">
|
||||||
{positions.length ? (
|
{positions.length ? (
|
||||||
positions.map((position, i) => {
|
positions.map((position) => {
|
||||||
const { stakeBalance, borrowBalance, bank, acct } = position
|
return position.bank ? (
|
||||||
return bank ? (
|
<PositionItem
|
||||||
<div
|
key={position.bank.name}
|
||||||
className="rounded-2xl border-2 border-th-fgd-1 bg-th-bkg-1 p-6"
|
position={position}
|
||||||
key={i + stakeBalance}
|
setActiveTab={setActiveTab}
|
||||||
>
|
borrowBank={borrowBank}
|
||||||
<div className="mb-4 flex flex-col border-b border-th-bkg-3 pb-4 md:flex-row md:items-center md:justify-between">
|
/>
|
||||||
<div className="mb-4 flex items-center space-x-3 md:mb-0">
|
|
||||||
<div
|
|
||||||
className={`inner-shadow-bottom-sm 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`}
|
|
||||||
>
|
|
||||||
<TokenLogo bank={bank} size={32} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3>{formatTokenSymbol(bank.name)}</h3>
|
|
||||||
<span
|
|
||||||
className={`text-sm ${
|
|
||||||
stakeBalance ? 'text-th-fgd-1' : 'text-th-fgd-4'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{stakeBalance ? 'Opened 2 weeks ago' : 'No Position'}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button onClick={() => handleAddOrManagePosition(bank.name)}>
|
|
||||||
<span className="mt-1 text-base tracking-wider">
|
|
||||||
{stakeBalance ? 'Manage' : 'Add Position'}
|
|
||||||
</span>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<p className="mb-1 text-th-fgd-4">Position Size</p>
|
|
||||||
<span className="text-xl font-bold text-th-fgd-1">
|
|
||||||
<FormatNumericValue value={stakeBalance} decimals={6} />{' '}
|
|
||||||
{formatTokenSymbol(bank.name)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="mb-1 text-th-fgd-4">Est. APY</p>
|
|
||||||
<span className="text-xl font-bold text-th-fgd-1">
|
|
||||||
{loadingRates ? (
|
|
||||||
<SheenLoader className="mt-1">
|
|
||||||
<div className="h-6 w-16 bg-th-bkg-2" />
|
|
||||||
</SheenLoader>
|
|
||||||
) : stakeRates?.[bank.name.toLowerCase()] ? (
|
|
||||||
`${(
|
|
||||||
stakeRates?.[bank.name.toLowerCase()] * 100
|
|
||||||
).toFixed(1)}%`
|
|
||||||
) : null}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="mb-1 text-th-fgd-4">Leverage</p>
|
|
||||||
<span className="text-xl font-bold text-th-fgd-1">
|
|
||||||
{group && acct
|
|
||||||
? getLeverage(group, acct).toFixed(2)
|
|
||||||
: 0.0}
|
|
||||||
x
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/* <div>
|
|
||||||
<p className="mb-1 text-th-fgd-4">Earned</p>
|
|
||||||
<span className="text-xl font-bold text-th-fgd-1">
|
|
||||||
{stakeBalance
|
|
||||||
? `X.XX ${formatTokenSymbol(bank.name)}`
|
|
||||||
: `0 ${formatTokenSymbol(bank.name)}`}
|
|
||||||
</span>
|
|
||||||
</div> */}
|
|
||||||
<div>
|
|
||||||
<p className="mb-1 text-th-fgd-4">Est. Liquidation Ratio</p>
|
|
||||||
<span className="whitespace-nowrap text-xl font-bold text-th-fgd-1">
|
|
||||||
{borrowBalance && borrowBank
|
|
||||||
? getLiquidationRatio(
|
|
||||||
borrowBalance,
|
|
||||||
stakeBalance,
|
|
||||||
bank,
|
|
||||||
borrowBank,
|
|
||||||
)
|
|
||||||
: '0.00'}{' '}
|
|
||||||
{`${formatTokenSymbol(bank.name)}/${BORROW_TOKEN}`}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null
|
) : null
|
||||||
})
|
})
|
||||||
) : (
|
) : (
|
||||||
|
@ -220,4 +121,113 @@ const Positions = ({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PositionItem = ({
|
||||||
|
position,
|
||||||
|
setActiveTab,
|
||||||
|
borrowBank,
|
||||||
|
}: {
|
||||||
|
position: Position
|
||||||
|
setActiveTab: (v: string) => void
|
||||||
|
borrowBank: Bank | undefined
|
||||||
|
}) => {
|
||||||
|
const { group } = useMangoGroup()
|
||||||
|
const { stakeBalance, borrowBalance, bank, acct } = position
|
||||||
|
|
||||||
|
const handleAddOrManagePosition = (token: string) => {
|
||||||
|
setActiveTab('Stake')
|
||||||
|
set((state) => {
|
||||||
|
state.selectedToken = token
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const leverage = useMemo(() => {
|
||||||
|
if (!group || !acct) return 0
|
||||||
|
const accountValue = toUiDecimalsForQuote(acct.getEquity(group).toNumber())
|
||||||
|
|
||||||
|
const assetsValue = toUiDecimalsForQuote(
|
||||||
|
acct.getAssetsValue(group).toNumber(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isNaN(assetsValue / accountValue)) {
|
||||||
|
return 0
|
||||||
|
} else {
|
||||||
|
return Math.abs(1 - assetsValue / accountValue) + 1
|
||||||
|
}
|
||||||
|
}, [group, acct])
|
||||||
|
|
||||||
|
const { estimatedNetAPY } = useBankRates(bank.name, leverage)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rounded-2xl border-2 border-th-fgd-1 bg-th-bkg-1 p-6">
|
||||||
|
<div className="mb-4 flex flex-col border-b border-th-bkg-3 pb-4 md:flex-row md:items-center md:justify-between">
|
||||||
|
<div className="mb-4 flex items-center space-x-3 md:mb-0">
|
||||||
|
<div
|
||||||
|
className={`inner-shadow-bottom-sm 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`}
|
||||||
|
>
|
||||||
|
<TokenLogo bank={bank} size={32} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>{formatTokenSymbol(bank.name)}</h3>
|
||||||
|
<span
|
||||||
|
className={`text-sm ${
|
||||||
|
stakeBalance ? 'text-th-fgd-1' : 'text-th-fgd-4'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{stakeBalance ? 'Opened 2 weeks ago' : 'No Position'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button onClick={() => handleAddOrManagePosition(bank.name)}>
|
||||||
|
<span className="mt-1 text-base tracking-wider">
|
||||||
|
{stakeBalance ? 'Manage' : 'Add Position'}
|
||||||
|
</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<p className="mb-1 text-th-fgd-4">Position Size</p>
|
||||||
|
<span className="text-xl font-bold text-th-fgd-1">
|
||||||
|
<FormatNumericValue value={stakeBalance} decimals={6} />{' '}
|
||||||
|
{formatTokenSymbol(bank.name)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="mb-1 text-th-fgd-4">Est. APY</p>
|
||||||
|
<span className="text-xl font-bold text-th-fgd-1">
|
||||||
|
<FormatNumericValue value={estimatedNetAPY} decimals={2} />%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="mb-1 text-th-fgd-4">Leverage</p>
|
||||||
|
<span className="text-xl font-bold text-th-fgd-1">
|
||||||
|
{leverage ? leverage.toFixed(2) : 0.0}x
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* <div>
|
||||||
|
<p className="mb-1 text-th-fgd-4">Earned</p>
|
||||||
|
<span className="text-xl font-bold text-th-fgd-1">
|
||||||
|
{stakeBalance
|
||||||
|
? `X.XX ${formatTokenSymbol(bank.name)}`
|
||||||
|
: `0 ${formatTokenSymbol(bank.name)}`}
|
||||||
|
</span>
|
||||||
|
</div> */}
|
||||||
|
<div>
|
||||||
|
<p className="mb-1 text-th-fgd-4">Est. Liquidation Ratio</p>
|
||||||
|
<span className="whitespace-nowrap text-xl font-bold text-th-fgd-1">
|
||||||
|
{borrowBalance && borrowBank
|
||||||
|
? getLiquidationRatio(
|
||||||
|
borrowBalance,
|
||||||
|
stakeBalance,
|
||||||
|
bank,
|
||||||
|
borrowBank,
|
||||||
|
)
|
||||||
|
: '0.00'}{' '}
|
||||||
|
{`${formatTokenSymbol(bank.name)}/${BORROW_TOKEN}`}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default Positions
|
export default Positions
|
||||||
|
|
|
@ -13,7 +13,7 @@ const TokenButton = ({
|
||||||
handleTokenSelect: (v: string) => void
|
handleTokenSelect: (v: string) => void
|
||||||
}) => {
|
}) => {
|
||||||
const leverage = useLeverageMax(tokenName)
|
const leverage = useLeverageMax(tokenName)
|
||||||
const { estimatedNetAPY } = useBankRates(tokenName, leverage)
|
const { estimatedMaxAPY } = useBankRates(tokenName, leverage)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
@ -59,7 +59,7 @@ const TokenButton = ({
|
||||||
// />
|
// />
|
||||||
// </SheenLoader>
|
// </SheenLoader>
|
||||||
// ) :
|
// ) :
|
||||||
`${estimatedNetAPY.toFixed(2)}%`
|
`${estimatedMaxAPY.toFixed(2)}%`
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import { useEffect, useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import useStakeRates from './useStakeRates'
|
import useStakeRates from './useStakeRates'
|
||||||
import useMangoGroup from './useMangoGroup'
|
import useMangoGroup from './useMangoGroup'
|
||||||
import mangoStore from '@store/mangoStore'
|
// import mangoStore from '@store/mangoStore'
|
||||||
|
import useLeverageMax from './useLeverageMax'
|
||||||
|
|
||||||
const set = mangoStore.getState().set
|
// const set = mangoStore.getState().set
|
||||||
|
|
||||||
export default function useBankRates(selectedToken: string, leverage: number) {
|
export default function useBankRates(selectedToken: string, leverage: number) {
|
||||||
const { data: stakeRates } = useStakeRates()
|
const { data: stakeRates } = useStakeRates()
|
||||||
const { group } = useMangoGroup()
|
const { group } = useMangoGroup()
|
||||||
const estimatedMaxAPY = mangoStore((s) => s.estimatedMaxAPY.current)
|
// const estimatedMaxAPY = mangoStore((s) => s.estimatedMaxAPY.current)
|
||||||
|
const leverageMax = useLeverageMax(selectedToken)
|
||||||
|
|
||||||
const stakeBank = useMemo(() => {
|
const stakeBank = useMemo(() => {
|
||||||
return group?.banksMapByName.get(selectedToken)?.[0]
|
return group?.banksMapByName.get(selectedToken)?.[0]
|
||||||
|
@ -40,12 +42,20 @@ export default function useBankRates(selectedToken: string, leverage: number) {
|
||||||
)
|
)
|
||||||
}, [borrowBankStakeRate, leverage, borrowBankBorrowRate])
|
}, [borrowBankStakeRate, leverage, borrowBankBorrowRate])
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
set((s) => {
|
// set((s) => {
|
||||||
s.estimatedMaxAPY.current =
|
// s.estimatedMaxAPY.current =
|
||||||
borrowBankStakeRate * 3 - borrowBankBorrowRate * 2
|
// borrowBankStakeRate * leverageMax -
|
||||||
})
|
// borrowBankBorrowRate * (leverageMax - 1)
|
||||||
}, [borrowBankStakeRate, borrowBankBorrowRate])
|
// })
|
||||||
|
// }, [borrowBankStakeRate, borrowBankBorrowRate, leverageMax])
|
||||||
|
|
||||||
|
const estimatedMaxAPY = useMemo(() => {
|
||||||
|
return (
|
||||||
|
borrowBankStakeRate * leverageMax -
|
||||||
|
borrowBankBorrowRate * (leverageMax - 1)
|
||||||
|
)
|
||||||
|
}, [borrowBankStakeRate, borrowBankBorrowRate, leverageMax])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stakeBankDepositRate,
|
stakeBankDepositRate,
|
||||||
|
|
Loading…
Reference in New Issue