2021-08-14 13:05:31 -07:00
|
|
|
import { useCallback, useMemo, useState } from 'react'
|
2021-07-20 07:21:58 -07:00
|
|
|
import FloatingElement from './FloatingElement'
|
|
|
|
import { ElementTitle } from './styles'
|
2021-08-14 13:05:31 -07:00
|
|
|
import useMangoStore, { mangoClient } from '../stores/useMangoStore'
|
2021-08-15 10:06:52 -07:00
|
|
|
import {
|
|
|
|
ceilToDecimal,
|
|
|
|
floorToDecimal,
|
|
|
|
i80f48ToPercent,
|
|
|
|
formatUsdValue,
|
|
|
|
} from '../utils/index'
|
2021-07-20 07:21:58 -07:00
|
|
|
import DepositModal from './DepositModal'
|
|
|
|
import WithdrawModal from './WithdrawModal'
|
2021-08-14 11:16:15 -07:00
|
|
|
import Button from './Button'
|
2021-07-20 07:21:58 -07:00
|
|
|
import Tooltip from './Tooltip'
|
|
|
|
import SideBadge from './SideBadge'
|
2021-08-14 13:05:31 -07:00
|
|
|
import {
|
|
|
|
getMarketIndexBySymbol,
|
|
|
|
nativeI80F48ToUi,
|
|
|
|
PerpAccount,
|
|
|
|
PerpMarket,
|
|
|
|
QUOTE_INDEX,
|
|
|
|
ZERO_BN,
|
|
|
|
} from '@blockworks-foundation/mango-client'
|
|
|
|
import useTradeHistory from '../hooks/useTradeHistory'
|
2021-08-15 10:06:52 -07:00
|
|
|
import { getAvgEntryPrice, getBreakEvenPrice } from './PerpPositionsTable'
|
2021-08-14 13:05:31 -07:00
|
|
|
import { notify } from '../utils/notifications'
|
|
|
|
|
|
|
|
const handleSettlePnl = async (
|
|
|
|
perpMarket: PerpMarket,
|
|
|
|
perpAccount: PerpAccount
|
|
|
|
) => {
|
|
|
|
const mangoAccount = useMangoStore.getState().selectedMangoAccount.current
|
|
|
|
const mangoGroup = useMangoStore.getState().selectedMangoGroup.current
|
|
|
|
const mangoCache = useMangoStore.getState().selectedMangoGroup.cache
|
|
|
|
const wallet = useMangoStore.getState().wallet.current
|
|
|
|
const actions = useMangoStore.getState().actions
|
|
|
|
const marketIndex = mangoGroup.getPerpMarketIndex(perpMarket.publicKey)
|
|
|
|
|
|
|
|
try {
|
|
|
|
const txid = await mangoClient.settlePnl(
|
|
|
|
mangoGroup,
|
|
|
|
mangoAccount,
|
|
|
|
perpMarket,
|
|
|
|
mangoGroup.rootBankAccounts[QUOTE_INDEX],
|
|
|
|
mangoCache.priceCache[marketIndex].price,
|
|
|
|
wallet
|
|
|
|
)
|
|
|
|
actions.fetchMangoAccounts()
|
|
|
|
notify({
|
|
|
|
title: 'Successfully settled PNL',
|
|
|
|
description: '',
|
|
|
|
txid,
|
|
|
|
})
|
|
|
|
} catch (e) {
|
|
|
|
console.log('Error settling PNL: ', `${e}`, `${perpAccount}`)
|
|
|
|
notify({
|
|
|
|
title: 'Error settling PNL',
|
|
|
|
description: e.message,
|
|
|
|
txid: e.txid,
|
|
|
|
type: 'error',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-07-20 07:21:58 -07:00
|
|
|
|
|
|
|
export default function MarketPosition() {
|
2021-08-14 13:05:31 -07:00
|
|
|
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
|
|
|
const mangoGroupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
|
|
|
|
const mangoGroupCache = useMangoStore((s) => s.selectedMangoGroup.cache)
|
|
|
|
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
|
|
|
|
const selectedMarket = useMangoStore((s) => s.selectedMarket.current)
|
2021-07-20 07:21:58 -07:00
|
|
|
const marketConfig = useMangoStore((s) => s.selectedMarket.config)
|
2021-08-14 13:05:31 -07:00
|
|
|
const connected = useMangoStore((s) => s.wallet.connected)
|
2021-07-20 07:21:58 -07:00
|
|
|
const baseSymbol = marketConfig.baseSymbol
|
2021-08-14 13:05:31 -07:00
|
|
|
const marketName = marketConfig.name
|
|
|
|
const tradeHistory = useTradeHistory()
|
|
|
|
const perpTradeHistory = tradeHistory?.filter(
|
|
|
|
(t) => t.marketName === marketName
|
2021-07-20 07:21:58 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
const [showDepositModal, setShowDepositModal] = useState(false)
|
|
|
|
const [showWithdrawModal, setShowWithdrawModal] = useState(false)
|
|
|
|
|
2021-08-14 13:05:31 -07:00
|
|
|
const marketIndex = useMemo(() => {
|
|
|
|
return getMarketIndexBySymbol(mangoGroupConfig, baseSymbol)
|
|
|
|
}, [mangoGroupConfig, baseSymbol])
|
|
|
|
|
|
|
|
const perpAccount = useMemo(() => {
|
|
|
|
if (marketName.includes('PERP') && mangoAccount) {
|
|
|
|
return mangoAccount.perpAccounts[marketIndex]
|
|
|
|
}
|
|
|
|
}, [marketName, mangoAccount, marketIndex])
|
|
|
|
|
2021-07-20 07:21:58 -07:00
|
|
|
const handleCloseDeposit = useCallback(() => {
|
|
|
|
setShowDepositModal(false)
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
const handleCloseWithdraw = useCallback(() => {
|
|
|
|
setShowWithdrawModal(false)
|
|
|
|
}, [])
|
|
|
|
|
2021-08-14 13:05:31 -07:00
|
|
|
return selectedMarket instanceof PerpMarket ? (
|
2021-07-22 04:34:03 -07:00
|
|
|
<FloatingElement showConnect>
|
2021-08-14 11:16:15 -07:00
|
|
|
<div className={!connected ? 'filter blur-sm' : null}>
|
2021-07-22 04:34:03 -07:00
|
|
|
<ElementTitle>Position</ElementTitle>
|
2021-07-21 09:34:59 -07:00
|
|
|
<div className={`flex items-center justify-between pt-1 pb-2`}>
|
2021-07-20 07:21:58 -07:00
|
|
|
<div className="font-normal text-th-fgd-3 leading-4">Side</div>
|
2021-08-14 13:05:31 -07:00
|
|
|
{perpAccount && !perpAccount.basePosition.eq(ZERO_BN) ? (
|
|
|
|
<SideBadge
|
|
|
|
side={perpAccount.basePosition.gt(ZERO_BN) ? 'long' : 'short'}
|
|
|
|
/>
|
|
|
|
) : (
|
2021-08-15 06:31:59 -07:00
|
|
|
'--'
|
2021-08-14 13:05:31 -07:00
|
|
|
)}
|
2021-07-20 07:21:58 -07:00
|
|
|
</div>
|
|
|
|
<div className={`flex justify-between pt-2 pb-2`}>
|
2021-08-14 13:05:31 -07:00
|
|
|
<div className="font-normal text-th-fgd-3 leading-4">
|
|
|
|
Position size
|
|
|
|
</div>
|
|
|
|
<div className={`text-th-fgd-1`}>
|
|
|
|
{perpAccount
|
|
|
|
? selectedMarket.baseLotsToNumber(perpAccount.basePosition)
|
|
|
|
: 0}{' '}
|
|
|
|
{baseSymbol}
|
|
|
|
</div>
|
2021-07-20 07:21:58 -07:00
|
|
|
</div>
|
|
|
|
<div className={`flex justify-between pt-2 pb-2`}>
|
|
|
|
<div className="font-normal text-th-fgd-3 leading-4">
|
2021-08-14 13:05:31 -07:00
|
|
|
Notional size
|
|
|
|
</div>
|
|
|
|
<div className={`text-th-fgd-1`}>
|
|
|
|
{perpAccount
|
2021-08-15 06:31:59 -07:00
|
|
|
? formatUsdValue(
|
2021-08-14 13:05:31 -07:00
|
|
|
selectedMarket.baseLotsToNumber(perpAccount.basePosition) *
|
|
|
|
mangoGroup.getPrice(marketIndex, mangoGroupCache).toNumber()
|
|
|
|
)
|
|
|
|
: 0}
|
2021-07-20 07:21:58 -07:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className={`flex justify-between pt-2 pb-2`}>
|
2021-08-14 13:05:31 -07:00
|
|
|
<div className="font-normal text-th-fgd-3 leading-4">
|
|
|
|
Avg entry price
|
|
|
|
</div>
|
|
|
|
<div className={`text-th-fgd-1`}>
|
|
|
|
{perpAccount
|
|
|
|
? getAvgEntryPrice(
|
|
|
|
mangoAccount,
|
|
|
|
perpAccount,
|
|
|
|
selectedMarket,
|
|
|
|
perpTradeHistory
|
|
|
|
)
|
|
|
|
: 0}
|
|
|
|
</div>
|
2021-07-20 07:21:58 -07:00
|
|
|
</div>
|
|
|
|
<div className={`flex justify-between pt-2 pb-2`}>
|
|
|
|
<div className="font-normal text-th-fgd-3 leading-4">
|
2021-08-14 13:05:31 -07:00
|
|
|
Break-even price
|
|
|
|
</div>
|
|
|
|
<div className={`text-th-fgd-1`}>
|
|
|
|
{perpAccount
|
|
|
|
? getBreakEvenPrice(
|
|
|
|
mangoAccount,
|
|
|
|
perpAccount,
|
|
|
|
selectedMarket,
|
|
|
|
perpTradeHistory
|
|
|
|
)
|
|
|
|
: 0}
|
2021-07-20 07:21:58 -07:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className={`flex justify-between pt-2 pb-2`}>
|
2021-08-14 13:05:31 -07:00
|
|
|
<div className="font-normal text-th-fgd-3 leading-4">
|
|
|
|
Unsettled PnL
|
|
|
|
</div>
|
|
|
|
<div className={`text-th-fgd-1`}>
|
|
|
|
{perpAccount
|
2021-08-15 06:31:59 -07:00
|
|
|
? formatUsdValue(
|
2021-08-14 13:05:31 -07:00
|
|
|
+nativeI80F48ToUi(
|
|
|
|
perpAccount.getPnl(
|
|
|
|
mangoGroup.perpMarkets[marketIndex],
|
|
|
|
mangoGroupCache.priceCache[marketIndex].price
|
|
|
|
),
|
|
|
|
marketConfig.quoteDecimals
|
|
|
|
)
|
|
|
|
)
|
|
|
|
: '0'}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className="flex">
|
|
|
|
{perpAccount ? (
|
|
|
|
<Button
|
|
|
|
className="mt-4 w-full"
|
|
|
|
disabled={!connected}
|
|
|
|
onClick={() => handleSettlePnl(selectedMarket, perpAccount)}
|
2021-07-20 07:21:58 -07:00
|
|
|
>
|
2021-08-14 13:05:31 -07:00
|
|
|
Settle PNL
|
|
|
|
</Button>
|
|
|
|
) : null}
|
2021-07-20 07:21:58 -07:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</FloatingElement>
|
|
|
|
) : (
|
|
|
|
<>
|
2021-07-22 04:34:03 -07:00
|
|
|
<FloatingElement showConnect>
|
2021-08-14 11:16:15 -07:00
|
|
|
<div className={!connected ? 'filter blur' : null}>
|
2021-07-22 04:34:03 -07:00
|
|
|
<ElementTitle>Balances</ElementTitle>
|
2021-08-14 13:05:31 -07:00
|
|
|
{mangoGroup ? (
|
2021-07-22 05:25:18 -07:00
|
|
|
<div className="grid grid-cols-2 grid-rows-1 gap-4 pt-2">
|
2021-08-14 13:05:31 -07:00
|
|
|
{mangoGroupConfig.tokens
|
2021-07-22 04:34:03 -07:00
|
|
|
.filter((t) => t.symbol === baseSymbol || t.symbol === 'USDC')
|
|
|
|
.reverse()
|
|
|
|
.map(({ symbol, mintKey }) => {
|
2021-08-14 13:05:31 -07:00
|
|
|
const tokenIndex = mangoGroup.getTokenIndex(mintKey)
|
2021-07-22 04:34:03 -07:00
|
|
|
return (
|
|
|
|
<div
|
2021-08-15 06:31:59 -07:00
|
|
|
className="border border-th-bkg-4 mb-4 p-3 rounded-md"
|
2021-07-22 04:34:03 -07:00
|
|
|
key={mintKey.toString()}
|
|
|
|
>
|
2021-08-15 06:31:59 -07:00
|
|
|
<div className="border-b border-th-bkg-4 flex items-center justify-between mb-3 pb-3">
|
2021-07-22 04:34:03 -07:00
|
|
|
<div className="flex items-center">
|
|
|
|
<img
|
|
|
|
alt=""
|
|
|
|
src={`/assets/icons/${symbol.toLowerCase()}.svg`}
|
|
|
|
className={`h-5 mr-2.5 w-auto`}
|
|
|
|
/>
|
|
|
|
<span className="text-th-fgd-2">{symbol}</span>
|
|
|
|
</div>
|
2021-07-20 07:21:58 -07:00
|
|
|
</div>
|
2021-07-23 07:07:05 -07:00
|
|
|
<div className="pb-3">
|
|
|
|
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
|
|
|
Deposits
|
|
|
|
</div>
|
2021-07-22 05:25:18 -07:00
|
|
|
<div className={`text-th-fgd-1`}>
|
2021-08-14 13:05:31 -07:00
|
|
|
{mangoAccount
|
2021-08-15 10:06:52 -07:00
|
|
|
? floorToDecimal(
|
|
|
|
mangoAccount
|
|
|
|
.getUiDeposit(
|
|
|
|
mangoGroupCache.rootBankCache[tokenIndex],
|
|
|
|
mangoGroup,
|
|
|
|
tokenIndex
|
|
|
|
)
|
|
|
|
.toNumber(),
|
|
|
|
mangoGroup.tokens[tokenIndex].decimals
|
|
|
|
)
|
|
|
|
: (0).toFixed(
|
|
|
|
mangoGroup.tokens[tokenIndex].decimals
|
|
|
|
)}
|
2021-07-20 07:21:58 -07:00
|
|
|
</div>
|
2021-07-22 05:25:18 -07:00
|
|
|
</div>
|
2021-07-23 07:07:05 -07:00
|
|
|
<div className="pb-3">
|
|
|
|
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
|
|
|
Borrows
|
|
|
|
</div>
|
2021-07-22 05:25:18 -07:00
|
|
|
<div className={`text-th-fgd-1`}>
|
2021-08-14 13:05:31 -07:00
|
|
|
{mangoAccount
|
2021-08-15 10:06:52 -07:00
|
|
|
? ceilToDecimal(
|
|
|
|
mangoAccount
|
|
|
|
.getUiBorrow(
|
|
|
|
mangoGroupCache.rootBankCache[tokenIndex],
|
|
|
|
mangoGroup,
|
|
|
|
tokenIndex
|
|
|
|
)
|
|
|
|
.toNumber(),
|
|
|
|
mangoGroup.tokens[tokenIndex].decimals
|
|
|
|
)
|
|
|
|
: (0).toFixed(
|
|
|
|
mangoGroup.tokens[tokenIndex].decimals
|
|
|
|
)}
|
2021-07-22 04:34:03 -07:00
|
|
|
</div>
|
2021-07-22 05:25:18 -07:00
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<Tooltip content="Deposit APY and Borrow APR">
|
|
|
|
<div
|
2021-07-23 07:07:05 -07:00
|
|
|
className={`cursor-help font-normal pb-0.5 text-th-fgd-3 text-xs default-transition hover:border-th-bkg-2 hover:text-th-fgd-3`}
|
2021-07-22 05:25:18 -07:00
|
|
|
>
|
|
|
|
Interest Rates
|
2021-07-20 07:21:58 -07:00
|
|
|
</div>
|
2021-07-22 05:25:18 -07:00
|
|
|
</Tooltip>
|
|
|
|
<div className={`text-th-fgd-1`}>
|
|
|
|
<span className={`text-th-green`}>
|
|
|
|
{i80f48ToPercent(
|
2021-08-14 13:05:31 -07:00
|
|
|
mangoGroup.getDepositRate(tokenIndex)
|
2021-07-22 05:25:18 -07:00
|
|
|
).toFixed(2)}
|
|
|
|
%
|
|
|
|
</span>
|
|
|
|
<span className={`text-th-fgd-4`}>{' / '}</span>
|
|
|
|
<span className={`text-th-red`}>
|
|
|
|
{i80f48ToPercent(
|
2021-08-14 13:05:31 -07:00
|
|
|
mangoGroup.getBorrowRate(tokenIndex)
|
2021-07-22 05:25:18 -07:00
|
|
|
).toFixed(2)}
|
|
|
|
%
|
|
|
|
</span>
|
2021-07-20 07:21:58 -07:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-07-22 04:34:03 -07:00
|
|
|
)
|
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
) : null}
|
2021-07-22 05:25:18 -07:00
|
|
|
<div className={`grid grid-cols-2 grid-rows-1 gap-4 pt-2`}>
|
|
|
|
<Button
|
|
|
|
onClick={() => setShowDepositModal(true)}
|
|
|
|
className="w-full"
|
|
|
|
disabled={!connected}
|
|
|
|
>
|
|
|
|
<span>Deposit</span>
|
|
|
|
</Button>
|
|
|
|
<Button
|
|
|
|
onClick={() => setShowWithdrawModal(true)}
|
|
|
|
className="w-full"
|
|
|
|
disabled={!connected}
|
|
|
|
>
|
|
|
|
<span>Withdraw</span>
|
|
|
|
</Button>
|
|
|
|
</div>
|
2021-07-22 04:34:03 -07:00
|
|
|
</div>
|
2021-07-20 07:21:58 -07:00
|
|
|
</FloatingElement>
|
|
|
|
{showDepositModal && (
|
|
|
|
<DepositModal isOpen={showDepositModal} onClose={handleCloseDeposit} />
|
|
|
|
)}
|
|
|
|
{showWithdrawModal && (
|
|
|
|
<WithdrawModal
|
|
|
|
isOpen={showWithdrawModal}
|
|
|
|
onClose={handleCloseWithdraw}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|