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 from './shared/Button'
import { formatTokenSymbol } 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 } from '@heroicons/react/20/solid'
import EditLeverageModal from './modals/EditLeverageModal'
import Tooltip from './shared/Tooltip'
import { useWallet } from '@solana/wallet-adapter-react'
const set = mangoStore.getState().set
export type Position = {
borrowBalance: number
stakeBalance: number
pnl: number
bank: Bank
acct: MangoAccount | undefined
}
const Positions = ({
setActiveTab,
}: {
setActiveTab: (tab: ActiveTab) => void
}) => {
const [showInactivePositions, setShowInactivePositions] =
useLocalStorageState(SHOW_INACTIVE_POSITIONS_KEY, true)
const { positions, jlpBorrowBank, lstBorrowBank } = usePositions(
showInactivePositions,
)
const numberOfPositions = useMemo(() => {
if (!positions.length) return 0
return positions.filter((pos) => pos.stakeBalance > 0).length
}, [positions])
return (
<>
{`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...
)}
>
)
}
const PositionItem = ({
position,
setActiveTab,
borrowBank,
}: {
position: Position
setActiveTab: (v: ActiveTab) => void
borrowBank: Bank | undefined
}) => {
const { connected } = useWallet()
const { jlpGroup, lstGroup } = useMangoGroup()
const { stakeBalance, bank, pnl, acct } = position
const handleAddOrManagePosition = (token: string) => {
setActiveTab('Boost!')
set((state) => {
state.selectedToken = token
})
}
const [showEditLeverageModal, setShowEditLeverageModal] = useState(false)
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])
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
return (
{formatTokenSymbol(bank.name)}
${bank.uiPrice.toFixed(2)}
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'
}`}
>
{stakeBalance || pnl ? (
) : (
'–'
)}
{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