import useMangoGroup from 'hooks/useMangoGroup' import { useMemo, useState } from 'react' import { SHOW_INACTIVE_POSITIONS_KEY } from 'utils/constants' import TokenLogo from './shared/TokenLogo' import Button, { IconButton } from './shared/Button' import { formatTokenSymbol, getStakableTokensDataForTokenName, } from 'utils/tokens' import mangoStore, { ActiveTab } from '@store/mangoStore' import Switch from './forms/Switch' import useLocalStorageState from 'hooks/useLocalStorageState' import FormatNumericValue from './shared/FormatNumericValue' import { Bank, MangoAccount, toUiDecimalsForQuote, } from '@blockworks-foundation/mango-v4' import useBankRates from 'hooks/useBankRates' import usePositions from 'hooks/usePositions' import { AdjustmentsHorizontalIcon, ArrowLeftIcon, } from '@heroicons/react/20/solid' import EditLeverageModal from './modals/EditLeverageModal' import Tooltip from './shared/Tooltip' import { useWallet } from '@solana/wallet-adapter-react' import UnstakeForm from './UnstakeForm' import StakeForm from './StakeForm' import DespositForm from './DepositForm' import { useTheme } from 'next-themes' const set = mangoStore.getState().set export type Position = { borrowBalance: number stakeBalance: number pnl: number solPnl: number | undefined bank: Bank acct: MangoAccount | undefined } const Positions = ({ setActiveTab, }: { setActiveTab: (tab: ActiveTab) => void }) => { const selectedToken = mangoStore((s) => s.selectedToken) const [showInactivePositions, setShowInactivePositions] = useLocalStorageState(SHOW_INACTIVE_POSITIONS_KEY, false) const { positions, jlpBorrowBank, lstBorrowBank } = usePositions( showInactivePositions, ) const [showAddRemove, setShowAddRemove] = useState('') const numberOfPositions = useMemo(() => { if (!positions.length) return 0 return positions.filter((pos) => pos.stakeBalance > 0).length }, [positions]) return !showAddRemove ? ( <>

{`You have ${numberOfPositions} active position${ numberOfPositions !== 1 ? 's' : '' }`}

setShowInactivePositions(checked)} > Show Inactive
{positions.length ? ( positions.map((position) => { const { bank } = position const isUsdcBorrow = bank.name === 'JLP' || bank.name === 'USDC' return position.bank ? ( ) : null }) ) : (
😑 Nothing to see here...
)}
) : (
setShowAddRemove('')} size="small" isPrimary>

{showAddRemove === 'add' ? 'Add' : 'Withdraw'} {selectedToken}

{showAddRemove === 'add' ? ( selectedToken === 'USDC' ? ( ) : ( ) ) : ( )}
) } const PositionItem = ({ position, setActiveTab, setShowAddRemove, borrowBank, }: { position: Position setActiveTab: (v: ActiveTab) => void setShowAddRemove: (v: 'add' | 'remove') => void borrowBank: Bank | undefined }) => { const { connected } = useWallet() const { theme } = useTheme() const { jlpGroup, lstGroup } = useMangoGroup() const { stakeBalance, bank, pnl, acct, solPnl } = position const [showEditLeverageModal, setShowEditLeverageModal] = useState(false) const isJlpGroup = bank.name === 'JLP' || bank.name === 'USDC' const handleAddNoPosition = (token: string) => { setActiveTab('Earn') set((state) => { state.selectedToken = token }) } const handleAddPosition = (token: string) => { setShowAddRemove('add') set((state) => { state.selectedToken = token }) } const handleRemovePosition = (token: string) => { setShowAddRemove('remove') set((state) => { state.selectedToken = token }) } const leverage = useMemo(() => { if (!acct || !bank) return 1 const isJlpGroup = bank.name === 'JLP' || bank.name === 'USDC' const group = isJlpGroup ? jlpGroup : lstGroup if (!group) return 1 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 } }, [acct, bank, jlpGroup, lstGroup, isJlpGroup]) const liquidationPrice = useMemo(() => { let price if (borrowBank?.name == 'SOL') { price = Number(bank?.uiPrice) / Number(borrowBank?.uiPrice) } else { price = Number(bank?.uiPrice) } const borrowMaintLiabWeight = Number(borrowBank?.maintLiabWeight) const stakeMaintAssetWeight = Number(bank?.maintAssetWeight) const loanOriginationFee = Number(borrowBank?.loanOriginationFeeRate) const liqPrice = price * ((borrowMaintLiabWeight * (1 + loanOriginationFee)) / stakeMaintAssetWeight) * (1 - 1 / leverage) return liqPrice.toFixed(2) }, [bank, borrowBank, leverage]) const { financialMetrics, stakeBankDepositRate, borrowBankBorrowRate } = useBankRates(bank.name, leverage) const APY_Daily_Compound = Math.pow(1 + Number(stakeBankDepositRate) / 365, 365) - 1 const uiRate = bank.name == 'USDC' ? APY_Daily_Compound * 100 : financialMetrics.APY const currentPnl = isJlpGroup ? pnl : solPnl return (

{formatTokenSymbol(bank.name)}

${bank.uiPrice.toFixed(2)}

{stakeBalance ? (
) : ( )}

Position Size

{' '} {'USDC'} {bank.name !== 'USDC' ? (

{' '} {formatTokenSymbol(bank.name)}

) : null}

Est. APY

{bank.name !== 'USDC' ? (

{formatTokenSymbol(bank.name)} Yield APY

{financialMetrics.collectedReturnsAPY > 0.01 ? '+' : ''} %

{formatTokenSymbol(bank.name)} Collateral Fee APY

0.01 ? 'text-th-error' : 'text-th-bkg-4' }`} > {financialMetrics?.collateralFeeAPY > 0.01 ? '-' : ''} %
{borrowBank ? ( <>

{`${borrowBank?.name} Borrow APY`}

0.01 ? 'text-th-error' : 'text-th-bkg-4' }`} > - %
) : null}
} > %
) : ( <> % )}

Total Earned

= 0 ? 'text-th-success' : 'text-th-error' }`} > {currentPnl ? ( <> {!isJlpGroup && ' SOL'} ) : ( '–' )}
{position.bank.name == 'USDC' ? null : ( <>

Leverage

{connected && stakeBalance && leverage ? `${leverage.toFixed(2)}x` : '–'} {connected && stakeBalance ? ( ) : null}

Est. Liquidation Price

{liquidationPrice} {borrowBank?.name == ' USDC' ? ' USDC' : ` ${bank?.name}/${borrowBank?.name}`}
{/* {liqPriceChangePercentage ? (

{liqPriceChangePercentage}%

) : null} */}
)}
{showEditLeverageModal ? ( { setShowEditLeverageModal(false) }} /> ) : null}
) } export default Positions