add market close to positions table (#365)

* add market close to positions table

* fix variable reference

* use secondary buttons
This commit is contained in:
saml33 2022-07-20 20:19:59 +10:00 committed by GitHub
parent dd1c0fab1d
commit f226e210ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 90 additions and 41 deletions

View File

@ -1,6 +1,10 @@
import { FunctionComponent, useState } from 'react' import { FunctionComponent, useState } from 'react'
import useMangoStore from '../stores/useMangoStore' import useMangoStore from '../stores/useMangoStore'
import { PerpMarket, ZERO_BN } from '@blockworks-foundation/mango-client' import {
MarketConfig,
PerpMarket,
ZERO_BN,
} from '@blockworks-foundation/mango-client'
import Button, { LinkButton } from './Button' import Button, { LinkButton } from './Button'
import { notify } from '../utils/notifications' import { notify } from '../utils/notifications'
import Loading from './Loading' import Loading from './Loading'
@ -12,26 +16,26 @@ import { useWallet } from '@solana/wallet-adapter-react'
interface MarketCloseModalProps { interface MarketCloseModalProps {
onClose: () => void onClose: () => void
isOpen: boolean isOpen: boolean
market: PerpMarket position: {
marketIndex: number marketConfig: MarketConfig
perpMarket: PerpMarket
}
} }
const MarketCloseModal: FunctionComponent<MarketCloseModalProps> = ({ const MarketCloseModal: FunctionComponent<MarketCloseModalProps> = ({
onClose, onClose,
isOpen, isOpen,
market, position,
marketIndex,
}) => { }) => {
const { t } = useTranslation('common') const { t } = useTranslation('common')
const [submitting, setSubmitting] = useState(false) const [submitting, setSubmitting] = useState(false)
const { wallet } = useWallet() const { wallet } = useWallet()
const actions = useMangoStore((s) => s.actions) const actions = useMangoStore((s) => s.actions)
const config = useMangoStore.getState().selectedMarket.config const { marketConfig, perpMarket } = position
async function handleMarketClose() { async function handleMarketClose() {
const mangoAccount = useMangoStore.getState().selectedMangoAccount.current const mangoAccount = useMangoStore.getState().selectedMangoAccount.current
const mangoGroup = useMangoStore.getState().selectedMangoGroup.current const mangoGroup = useMangoStore.getState().selectedMangoGroup.current
const marketConfig = useMangoStore.getState().selectedMarket.config
const mangoClient = useMangoStore.getState().connection.client const mangoClient = useMangoStore.getState().connection.client
const askInfo = const askInfo =
useMangoStore.getState().accountInfos[marketConfig.asksKey.toString()] useMangoStore.getState().accountInfos[marketConfig.asksKey.toString()]
@ -51,11 +55,11 @@ const MarketCloseModal: FunctionComponent<MarketCloseModalProps> = ({
setSubmitting(true) setSubmitting(true)
try { try {
const perpAccount = mangoAccount.perpAccounts[marketIndex] const perpAccount = mangoAccount.perpAccounts[marketConfig.marketIndex]
const side = perpAccount.basePosition.gt(ZERO_BN) ? 'sell' : 'buy' const side = perpAccount.basePosition.gt(ZERO_BN) ? 'sell' : 'buy'
// send a large size to ensure we are reducing the entire position // send a large size to ensure we are reducing the entire position
const size = const size =
Math.abs(market.baseLotsToNumber(perpAccount.basePosition)) * 2 Math.abs(perpMarket.baseLotsToNumber(perpAccount.basePosition)) * 2
// hard coded for now; market orders are very dangerous and fault prone // hard coded for now; market orders are very dangerous and fault prone
const maxSlippage: number | undefined = 0.025 const maxSlippage: number | undefined = 0.025
@ -63,7 +67,7 @@ const MarketCloseModal: FunctionComponent<MarketCloseModalProps> = ({
const txid = await mangoClient.placePerpOrder2( const txid = await mangoClient.placePerpOrder2(
mangoGroup, mangoGroup,
mangoAccount, mangoAccount,
market, perpMarket,
wallet?.adapter, wallet?.adapter,
side, side,
referencePrice * (1 + (side === 'buy' ? 1 : -1) * maxSlippage), referencePrice * (1 + (side === 'buy' ? 1 : -1) * maxSlippage),
@ -93,9 +97,9 @@ const MarketCloseModal: FunctionComponent<MarketCloseModalProps> = ({
return ( return (
<Modal onClose={onClose} isOpen={isOpen}> <Modal onClose={onClose} isOpen={isOpen}>
<div className="pb-2 text-lg text-th-fgd-1"> <h2 className="mb-2">
{t('close-confirm', { config_name: config.name })} {t('close-confirm', { config_name: marketConfig.name })}
</div> </h2>
<div className="pb-6 text-th-fgd-3">{t('price-expect')}</div> <div className="pb-6 text-th-fgd-3">{t('price-expect')}</div>
<div className="flex items-center"> <div className="flex items-center">
<Button onClick={handleMarketClose}> <Button onClick={handleMarketClose}>

View File

@ -390,6 +390,7 @@ export default function MarketPosition() {
<Button <Button
onClick={() => setShowMarketCloseModal(true)} onClick={() => setShowMarketCloseModal(true)}
className="mt-2.5 w-full" className="mt-2.5 w-full"
primary={false}
> >
<span>{t('market-close')}</span> <span>{t('market-close')}</span>
</Button> </Button>
@ -399,8 +400,7 @@ export default function MarketPosition() {
<MarketCloseModal <MarketCloseModal
isOpen={showMarketCloseModal} isOpen={showMarketCloseModal}
onClose={handleCloseWarning} onClose={handleCloseWarning}
market={selectedMarket} position={{ marketConfig: marketConfig, perpMarket: selectedMarket }}
marketIndex={marketIndex}
/> />
) : null} ) : null}
</> </>

View File

@ -143,7 +143,7 @@ const DesktopTable = ({
)} $${order.triggerPrice.toFixed(2)}`} )} $${order.triggerPrice.toFixed(2)}`}
</Td> </Td>
<Td className="w-[14.286%]"> <Td className="w-[14.286%]">
<div className={`flex justify-end space-x-3`}> <div className={`flex justify-end space-x-2`}>
{editOrderIndex !== index ? ( {editOrderIndex !== index ? (
<> <>
{!order.perpTrigger ? ( {!order.perpTrigger ? (
@ -157,6 +157,7 @@ const DesktopTable = ({
<Button <Button
onClick={() => handleCancelOrder(order, market.account)} onClick={() => handleCancelOrder(order, market.account)}
className="-my-1 h-7 pt-0 pb-0 pl-3 pr-3 text-xs" className="-my-1 h-7 pt-0 pb-0 pl-3 pr-3 text-xs"
primary={false}
> >
{cancelledOrderId + '' === order.orderId + '' ? ( {cancelledOrderId + '' === order.orderId + '' ? (
<Loading /> <Loading />
@ -170,6 +171,7 @@ const DesktopTable = ({
<Button <Button
onClick={() => handleCancelAllOrders(market.account)} onClick={() => handleCancelAllOrders(market.account)}
className="-my-1 h-7 pt-0 pb-0 pl-3 pr-3 text-xs text-th-red" className="-my-1 h-7 pt-0 pb-0 pl-3 pr-3 text-xs text-th-red"
primary={false}
> >
{t('cancel-all') + ' ' + market.config.name} {t('cancel-all') + ' ' + market.config.name}
</Button> </Button>
@ -335,9 +337,7 @@ const MobileTable = ({
/> />
</div> </div>
<Button <Button
className={`${ className={`mt-4 h-8 pt-0 pb-0 pl-3 pr-3 text-xs`}
index % 2 === 0 ? 'bg-th-bkg-4' : 'bg-th-bkg-3'
} mt-4 h-8 pt-0 pb-0 pl-3 pr-3 text-xs`}
onClick={() => onClick={() =>
handleModifyOrder( handleModifyOrder(
order, order,

View File

@ -5,7 +5,7 @@ import { useTranslation } from 'next-i18next'
import { ExclamationIcon } from '@heroicons/react/solid' import { ExclamationIcon } from '@heroicons/react/solid'
import { ZERO_I80F48 } from '@blockworks-foundation/mango-client' import { ZERO_I80F48 } from '@blockworks-foundation/mango-client'
import useMangoStore from '../stores/useMangoStore' import useMangoStore from '../stores/useMangoStore'
import { LinkButton } from '../components/Button' import Button, { LinkButton } from '../components/Button'
import { useViewport } from '../hooks/useViewport' import { useViewport } from '../hooks/useViewport'
import { breakpoints } from './TradePageGrid' import { breakpoints } from './TradePageGrid'
import { ExpandableRow, Table, Td, Th, TrBody, TrHead } from './TableElements' import { ExpandableRow, Table, Td, Th, TrBody, TrHead } from './TableElements'
@ -33,6 +33,7 @@ const PositionsTable: React.FC = () => {
const { t } = useTranslation('common') const { t } = useTranslation('common')
const [showShareModal, setShowShareModal] = useState(false) const [showShareModal, setShowShareModal] = useState(false)
const [showMarketCloseModal, setShowMarketCloseModal] = useState(false) const [showMarketCloseModal, setShowMarketCloseModal] = useState(false)
const [positionToClose, setPositionToClose] = useState<any>(null)
const [positionToShare, setPositionToShare] = useState<any>(null) const [positionToShare, setPositionToShare] = useState<any>(null)
const [settleSinglePos, setSettleSinglePos] = useState(null) const [settleSinglePos, setSettleSinglePos] = useState(null)
@ -61,8 +62,20 @@ const PositionsTable: React.FC = () => {
} }
}, [openPositions]) }, [openPositions])
useEffect(() => {
if (positionToClose) {
const updatedPosition = openPositions.find(
(p) => p.marketConfig === positionToClose.marketConfig
)
if (updatedPosition) {
setPositionToClose(updatedPosition)
}
}
}, [openPositions])
const handleCloseWarning = useCallback(() => { const handleCloseWarning = useCallback(() => {
setShowMarketCloseModal(false) setShowMarketCloseModal(false)
setPositionToClose(null)
}, []) }, [])
const handleSizeClick = (size, indexPrice) => { const handleSizeClick = (size, indexPrice) => {
@ -87,6 +100,11 @@ const PositionsTable: React.FC = () => {
setShowShareModal(true) setShowShareModal(true)
} }
const handleShowMarketCloseModal = (position) => {
setPositionToClose(position)
setShowMarketCloseModal(true)
}
const handleSettlePnl = async (perpMarket, perpAccount, index) => { const handleSettlePnl = async (perpMarket, perpAccount, index) => {
if (wallet) { if (wallet) {
setSettleSinglePos(index) setSettleSinglePos(index)
@ -177,7 +195,6 @@ const PositionsTable: React.FC = () => {
<Th>{t('market')}</Th> <Th>{t('market')}</Th>
<Th>{t('side')}</Th> <Th>{t('side')}</Th>
<Th>{t('position-size')}</Th> <Th>{t('position-size')}</Th>
<Th>{t('notional-size')}</Th>
<Th>{t('average-entry')}</Th> <Th>{t('average-entry')}</Th>
<Th>{t('break-even')}</Th> <Th>{t('break-even')}</Th>
<Th>{t('estimated-liq-price')}</Th> <Th>{t('estimated-liq-price')}</Th>
@ -260,15 +277,18 @@ const PositionsTable: React.FC = () => {
handleSizeClick(basePosition, indexPrice) handleSizeClick(basePosition, indexPrice)
} }
> >
{`${basePositionUi} ${marketConfig.baseSymbol}`} {`${basePositionUi} (${formatUsdValue(
Math.abs(notionalSize)
)})`}
</span> </span>
) : ( ) : (
<span> <span>
{`${basePositionUi} ${marketConfig.baseSymbol}`} {`${basePositionUi} (${formatUsdValue(
Math.abs(notionalSize)
)})`}
</span> </span>
)} )}
</Td> </Td>
<Td>{formatUsdValue(Math.abs(notionalSize))}</Td>
<Td> <Td>
{avgEntryPrice {avgEntryPrice
? formatUsdValue(avgEntryPrice) ? formatUsdValue(avgEntryPrice)
@ -322,23 +342,28 @@ const PositionsTable: React.FC = () => {
)} )}
</Td> </Td>
<Td> <Td>
<LinkButton <div className="flex items-center space-x-3">
onClick={() => <Button
handleShowShare(openPositions[index]) className="h-8 pt-0 pb-0 pl-3 pr-3 text-xs"
} primary={false}
disabled={!avgEntryPrice ? true : false} onClick={() =>
> handleShowMarketCloseModal(
<TwitterIcon className="h-4 w-4" /> openPositions[index]
</LinkButton> )
}
>
{t('market-close')}
</Button>
<LinkButton
onClick={() =>
handleShowShare(openPositions[index])
}
disabled={!avgEntryPrice ? true : false}
>
<TwitterIcon className="h-4 w-4" />
</LinkButton>
</div>
</Td> </Td>
{showMarketCloseModal ? (
<MarketCloseModal
isOpen={showMarketCloseModal}
onClose={handleCloseWarning}
market={perpMarket}
marketIndex={marketConfig.marketIndex}
/>
) : null}
</TrBody> </TrBody>
) )
} }
@ -489,6 +514,19 @@ const PositionsTable: React.FC = () => {
? usdFormatter(liquidationPrice) ? usdFormatter(liquidationPrice)
: 'N/A'} : 'N/A'}
</div> </div>
<div className="col-span-2">
<Button
className="w-full"
primary={false}
onClick={() =>
handleShowMarketCloseModal(
openPositions[index]
)
}
>
{t('market-close')}
</Button>
</div>
</div> </div>
} }
/> />
@ -513,6 +551,13 @@ const PositionsTable: React.FC = () => {
position={positionToShare!} position={positionToShare!}
/> />
) : null} ) : null}
{showMarketCloseModal ? (
<MarketCloseModal
isOpen={showMarketCloseModal}
onClose={handleCloseWarning}
position={positionToClose!}
/>
) : null}
</div> </div>
) )
} }

View File

@ -69,6 +69,7 @@ const RedeemButtons: React.FC = () => {
<Button <Button
className="flex h-7 items-center justify-center pt-0 pb-0 pl-3 pr-3 text-xs" className="flex h-7 items-center justify-center pt-0 pb-0 pl-3 pr-3 text-xs"
onClick={handleSettleAll} onClick={handleSettleAll}
primary={false}
> >
{settling ? <Loading /> : t('redeem-all')} {settling ? <Loading /> : t('redeem-all')}
</Button> </Button>

View File

@ -5,7 +5,6 @@ import {
createRef, createRef,
useState, useState,
} from 'react' } from 'react'
// import { getWeights, MarketConfig } from '@blockworks-foundation/mango-client'
import { MarketConfig } from '@blockworks-foundation/mango-client' import { MarketConfig } from '@blockworks-foundation/mango-client'
import useMangoStore from '../stores/useMangoStore' import useMangoStore from '../stores/useMangoStore'