lev-stake-sol/components/Positions.tsx

182 lines
6.9 KiB
TypeScript
Raw Normal View History

import useMangoGroup from 'hooks/useMangoGroup'
import { useMemo } from 'react'
2023-09-14 21:58:09 -07:00
import { SHOW_INACTIVE_POSITIONS_KEY, STAKEABLE_TOKENS } from 'utils/constants'
2023-09-14 21:24:29 -07:00
import TokenLogo from './shared/TokenLogo'
import Button from './shared/Button'
import { formatTokenSymbol } from 'utils/tokens'
import mangoStore from '@store/mangoStore'
2023-09-14 21:58:09 -07:00
import Switch from './forms/Switch'
import useLocalStorageState from 'hooks/useLocalStorageState'
2023-09-17 17:21:29 -07:00
import useStakeRates from 'hooks/useStakeRates'
import SheenLoader from './shared/SheenLoader'
import useStakeAccounts from 'hooks/useStakeAccounts'
import FormatNumericValue from './shared/FormatNumericValue'
2023-09-14 21:24:29 -07:00
const set = mangoStore.getState().set
2023-09-20 18:54:55 -07:00
const BORROW_TOKEN = 'SOL'
const getLeverage = (stakeBalance: number, borrowBalance: number) => {
if (stakeBalance === 0) return 0
return borrowBalance / stakeBalance
}
2023-09-14 21:24:29 -07:00
const Positions = ({
setActiveTab,
}: {
setActiveTab: (tab: string) => void
}) => {
const { group } = useMangoGroup()
2023-09-17 17:21:29 -07:00
const { data: stakeRates, isLoading: loadingRates } = useStakeRates()
2023-09-14 21:58:09 -07:00
const [showInactivePositions, setShowInactivePositions] =
useLocalStorageState(SHOW_INACTIVE_POSITIONS_KEY, true)
const { stakeAccounts } = useStakeAccounts()
2023-09-20 18:54:55 -07:00
const borrowBank = useMemo(() => {
return group?.banksMapByMint.get(BORROW_TOKEN)?.[0]
}, [group])
const banks = useMemo(() => {
if (!group) return []
const positionBanks = []
for (const token of STAKEABLE_TOKENS) {
2023-09-14 21:24:29 -07:00
const bank = group.banksMapByName.get(token)?.[0]
positionBanks.push(bank)
}
return positionBanks
}, [group])
const positions = useMemo(() => {
const positions = []
for (const bank of banks) {
if (!bank) continue
const acct = stakeAccounts?.find((acc) => acc.getTokenBalanceUi(bank) > 0)
2023-09-20 18:54:55 -07:00
const stakeBalance = acct ? acct.getTokenBalanceUi(bank) : 0
const borrowBalance =
acct && borrowBank ? acct.getTokenBalanceUi(borrowBank) : 0
positions.push({ borrowBalance, stakeBalance, bank })
}
2023-09-20 18:54:55 -07:00
const sortedPositions = positions.sort(
(a, b) => b.stakeBalance - a.stakeBalance,
)
2023-09-14 21:58:09 -07:00
return showInactivePositions
? sortedPositions
2023-09-20 18:54:55 -07:00
: sortedPositions.filter((pos) => pos.stakeBalance > 0)
}, [banks, showInactivePositions, stakeAccounts])
2023-09-14 21:58:09 -07:00
const numberOfPositions = useMemo(() => {
if (!positions.length) return 0
2023-09-20 18:54:55 -07:00
return positions.filter((pos) => pos.stakeBalance > 0).length
2023-09-14 21:58:09 -07:00
}, [positions])
2023-09-14 21:24:29 -07:00
const handleAddOrManagePosition = (token: string) => {
setActiveTab('Stake')
set((state) => {
state.selectedToken = token
})
}
2023-09-24 05:55:00 -07:00
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">
<p className="font-medium">{`You have ${numberOfPositions} active position${
numberOfPositions !== 1 ? 's' : ''
2023-09-14 21:58:09 -07:00
}`}</p>
<Switch
checked={showInactivePositions}
onChange={(checked) => setShowInactivePositions(checked)}
>
Show Inactive
</Switch>
</div>
2023-09-24 05:55:00 -07:00
<div className="grid grid-cols-1 gap-2">
{positions.length ? (
positions.map((position, i) => {
const {stakeBalance, borrowBalance, bank } = position
2023-09-24 05:55:00 -07:00
return bank ? (
<div
className="rounded-2xl border-2 border-th-fgd-1 bg-th-bkg-1 p-6"
key={i + stakeBalance}
2023-09-24 05:55:00 -07:00
>
<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`}
2023-09-14 22:57:39 -07:00
>
2023-09-24 05:55:00 -07:00
<TokenLogo bank={bank} size={32} />
</div>
<div>
2023-09-25 06:48:39 -07:00
<h3>{formatTokenSymbol(bank.name)}</h3>
2023-09-24 05:55:00 -07:00
<span
className={`text-sm ${
stakeBalance ? 'text-th-fgd-1' : 'text-th-fgd-4'
2023-09-24 05:55:00 -07:00
}`}
>
{stakeBalance ? 'Opened 2 weeks ago' : 'No Position'}
2023-09-24 05:55:00 -07:00
</span>
</div>
2023-09-14 22:57:39 -07:00
</div>
2023-09-24 05:55:00 -07:00
<Button onClick={() => handleAddOrManagePosition(bank.name)}>
<span className="mt-1 text-base tracking-wider">
{stakeBalance ? 'Manage' : 'Add Position'}
2023-09-24 05:55:00 -07:00
</span>
</Button>
2023-09-14 22:57:39 -07:00
</div>
2023-09-24 05:55:00 -07:00
<div className="grid grid-cols-2 gap-4">
<div>
<p className="mb-1 text-th-fgd-4">Position Size</p>
2023-09-25 06:48:39 -07:00
<span className="text-xl font-bold text-th-fgd-1">
<FormatNumericValue value={stakeBalance} decimals={6} />{' '}
2023-09-24 05:55:00 -07:00
{formatTokenSymbol(bank.name)}
</span>
</div>
<div>
<p className="mb-1 text-th-fgd-4">Est. APY</p>
2023-09-25 06:48:39 -07:00
<span className="text-xl font-bold text-th-fgd-1">
2023-09-24 05:55:00 -07:00
{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(2)}%`
) : null}
</span>
</div>
<div>
<p className="mb-1 text-th-fgd-4">Leverage</p>
2023-09-25 06:48:39 -07:00
<span className="text-xl font-bold text-th-fgd-1">
{getLeverage(stakeBalance, borrowBalance)}x
2023-09-24 05:55:00 -07:00
</span>
</div>
<div>
<p className="mb-1 text-th-fgd-4">Earned</p>
2023-09-25 06:48:39 -07:00
<span className="text-xl font-bold text-th-fgd-1">
{balance ? `X.XX ${formatTokenSymbol(bank.name)}` : `0 ${formatTokenSymbol(bank.name)}`}
2023-09-24 05:55:00 -07:00
</span>
</div>
<div>
<p className="mb-1 text-th-fgd-4">Liquidation Price</p>
2023-09-25 06:48:39 -07:00
<span className="whitespace-nowrap text-xl font-bold text-th-fgd-1">
{stakeBalance ? 'X.XX' : '0'}{' '}
{`${formatTokenSymbol(bank.name)}/${BORROW_TOKEN}`}
2023-09-24 05:55:00 -07:00
</span>
</div>
2023-09-14 21:24:29 -07:00
</div>
</div>
2023-09-24 05:55:00 -07:00
) : null
})
) : (
<div className="flex justify-center rounded-2xl border-2 border-th-fgd-1 bg-th-bkg-1 p-6">
<span>Nothing to see here...</span>
</div>
)}
2023-09-14 22:57:39 -07:00
</div>
2023-09-24 05:55:00 -07:00
</>
)
}
export default Positions