allow settle from token page

This commit is contained in:
saml33 2024-02-14 10:24:28 +11:00
parent 90b82943d4
commit 7a0c572e36
10 changed files with 95 additions and 72 deletions

View File

@ -76,8 +76,6 @@ const AccountTabs = () => {
} }
const TabContent = ({ activeTab }: { activeTab: string }) => { const TabContent = ({ activeTab }: { activeTab: string }) => {
const unsettledSpotBalances = useUnsettledSpotBalances()
const unsettledPerpPositions = useUnsettledPerpPositions()
switch (activeTab) { switch (activeTab) {
case 'overview': case 'overview':
return <AccountOverview /> return <AccountOverview />
@ -88,12 +86,7 @@ const TabContent = ({ activeTab }: { activeTab: string }) => {
case 'trade:orders': case 'trade:orders':
return <AccountOrders /> return <AccountOrders />
case 'trade:unsettled': case 'trade:unsettled':
return ( return <UnsettledTrades />
<UnsettledTrades
unsettledSpotBalances={unsettledSpotBalances}
unsettledPerpPositions={unsettledPerpPositions}
/>
)
case 'history': case 'history':
return <HistoryTabs /> return <HistoryTabs />
default: default:

View File

@ -1,8 +1,10 @@
import { Bank } from '@blockworks-foundation/mango-v4' import { Bank } from '@blockworks-foundation/mango-v4'
import DepositWithdrawModal from '@components/modals/DepositWithdrawModal' import DepositWithdrawModal from '@components/modals/DepositWithdrawModal'
import Button from '@components/shared/Button' import Button, { LinkButton } from '@components/shared/Button'
import FormatNumericValue from '@components/shared/FormatNumericValue' import FormatNumericValue from '@components/shared/FormatNumericValue'
import Modal from '@components/shared/Modal'
import Tooltip from '@components/shared/Tooltip' import Tooltip from '@components/shared/Tooltip'
import UnsettledTrades from '@components/trade/UnsettledTrades'
import { ArrowDownTrayIcon, ArrowUpTrayIcon } from '@heroicons/react/20/solid' import { ArrowDownTrayIcon, ArrowUpTrayIcon } from '@heroicons/react/20/solid'
import mangoStore from '@store/mangoStore' import mangoStore from '@store/mangoStore'
import useAccountInterest from 'hooks/useAccountInterest' import useAccountInterest from 'hooks/useAccountInterest'
@ -11,6 +13,8 @@ import useMangoAccount from 'hooks/useMangoAccount'
import useUnsettledPerpPositions from 'hooks/useUnsettledPerpPositions' import useUnsettledPerpPositions from 'hooks/useUnsettledPerpPositions'
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
import { ModalProps } from 'types/modal'
import { formatCurrencyValue } from 'utils/numbers'
const ActionPanel = ({ bank }: { bank: Bank }) => { const ActionPanel = ({ bank }: { bank: Bank }) => {
const { t } = useTranslation(['common', 'trade']) const { t } = useTranslation(['common', 'trade'])
@ -19,6 +23,7 @@ const ActionPanel = ({ bank }: { bank: Bank }) => {
const [showDepositModal, setShowDepositModal] = useState< const [showDepositModal, setShowDepositModal] = useState<
'deposit' | 'withdraw' | '' 'deposit' | 'withdraw' | ''
>('') >('')
const [showSettleModal, setShowSettleModal] = useState(false)
const { data: totalInterestData } = useAccountInterest() const { data: totalInterestData } = useAccountInterest()
const [depositRate, borrowRate] = useMemo(() => { const [depositRate, borrowRate] = useMemo(() => {
const depositRate = bank.getDepositRateUi() const depositRate = bank.getDepositRateUi()
@ -84,12 +89,7 @@ const ActionPanel = ({ bank }: { bank: Bank }) => {
<div className="flex justify-between border-t border-th-bkg-4 py-3"> <div className="flex justify-between border-t border-th-bkg-4 py-3">
<p>{t('collateral-value')}</p> <p>{t('collateral-value')}</p>
<p className="font-mono text-th-fgd-2"> <p className="font-mono text-th-fgd-2">
$ {mangoAccount ? formatCurrencyValue(collateralValue) : '$0.00'}
{mangoAccount ? (
<FormatNumericValue value={collateralValue} decimals={2} />
) : (
'0.00'
)}
</p> </p>
</div> </div>
<div className="flex justify-between border-t border-th-bkg-4 py-3"> <div className="flex justify-between border-t border-th-bkg-4 py-3">
@ -107,16 +107,21 @@ const ActionPanel = ({ bank }: { bank: Bank }) => {
</div> </div>
<div className="flex justify-between border-t border-th-bkg-4 py-3"> <div className="flex justify-between border-t border-th-bkg-4 py-3">
<p>{t('trade:unsettled')}</p> <p>{t('trade:unsettled')}</p>
<p className="font-mono text-th-fgd-2"> {unsettled ? (
{unsettled ? ( <div className="flex space-x-2">
<FormatNumericValue <p className="font-mono text-th-fgd-2">
value={unsettled} <FormatNumericValue
decimals={bank.mintDecimals} value={unsettled}
/> decimals={bank.mintDecimals}
) : ( />
0 </p>
)} <LinkButton onClick={() => setShowSettleModal(true)}>
</p> {t('trade:settle')}
</LinkButton>
</div>
) : (
<p className="font-mono text-th-fgd-2">0</p>
)}
</div> </div>
<div className="flex justify-between border-t border-th-bkg-4 py-3"> <div className="flex justify-between border-t border-th-bkg-4 py-3">
<p>{t('interest-earned')}</p> <p>{t('interest-earned')}</p>
@ -191,8 +196,26 @@ const ActionPanel = ({ bank }: { bank: Bank }) => {
token={bank?.name} token={bank?.name}
/> />
) : null} ) : null}
{showSettleModal ? (
<UnsettledModal
isOpen={showSettleModal}
onClose={() => setShowSettleModal(false)}
/>
) : null}
</> </>
) )
} }
export default ActionPanel export default ActionPanel
const UnsettledModal = ({ isOpen, onClose }: ModalProps) => {
const { t } = useTranslation('trade')
return (
<Modal isOpen={isOpen} onClose={onClose}>
<h2 className="mb-4 text-center md:mb-0">{t('unsettled-balances')}</h2>
<div className="border-t border-th-bkg-3 md:border-t-0">
<UnsettledTrades />
</div>
</Modal>
)
}

View File

@ -84,20 +84,13 @@ const TradeInfoTabs = () => {
export default TradeInfoTabs export default TradeInfoTabs
const TabContent = ({ selectedTab }: { selectedTab: string }) => { const TabContent = ({ selectedTab }: { selectedTab: string }) => {
const unsettledSpotBalances = useUnsettledSpotBalances()
const unsettledPerpPositions = useUnsettledPerpPositions()
switch (selectedTab) { switch (selectedTab) {
case 'balances': case 'balances':
return <SwapTradeBalances /> return <SwapTradeBalances />
case 'trade:orders': case 'trade:orders':
return <AccountOrders /> return <AccountOrders />
case 'trade:unsettled': case 'trade:unsettled':
return ( return <UnsettledTrades />
<UnsettledTrades
unsettledSpotBalances={unsettledSpotBalances}
unsettledPerpPositions={unsettledPerpPositions}
/>
)
case 'trade:positions': case 'trade:positions':
return <PerpPositions /> return <PerpPositions />
case 'trade-history': case 'trade-history':

View File

@ -12,7 +12,7 @@ import { useViewport } from 'hooks/useViewport'
import { breakpoints } from 'utils/theme' import { breakpoints } from 'utils/theme'
import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements' import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements'
import useMangoGroup from 'hooks/useMangoGroup' import useMangoGroup from 'hooks/useMangoGroup'
import { PerpMarket, PerpPosition } from '@blockworks-foundation/mango-v4' import { PerpMarket } from '@blockworks-foundation/mango-v4'
import TableMarketName from './TableMarketName' import TableMarketName from './TableMarketName'
import useMangoAccount from 'hooks/useMangoAccount' import useMangoAccount from 'hooks/useMangoAccount'
import { useWallet } from '@solana/wallet-adapter-react' import { useWallet } from '@solana/wallet-adapter-react'
@ -20,16 +20,14 @@ import ConnectEmptyState from '@components/shared/ConnectEmptyState'
import FormatNumericValue from '@components/shared/FormatNumericValue' import FormatNumericValue from '@components/shared/FormatNumericValue'
import useUnownedAccount from 'hooks/useUnownedAccount' import useUnownedAccount from 'hooks/useUnownedAccount'
import { isMangoError } from 'types' import { isMangoError } from 'types'
import { useUnsettledSpotBalances } from 'hooks/useUnsettledSpotBalances'
import useUnsettledPerpPositions from 'hooks/useUnsettledPerpPositions'
const UnsettledTrades = ({ const UnsettledTrades = () => {
unsettledSpotBalances,
unsettledPerpPositions,
}: {
unsettledSpotBalances: any
unsettledPerpPositions: PerpPosition[]
}) => {
const { t } = useTranslation(['common', 'trade']) const { t } = useTranslation(['common', 'trade'])
const { group } = useMangoGroup() const { group } = useMangoGroup()
const unsettledSpotBalances = useUnsettledSpotBalances()
const unsettledPerpPositions = useUnsettledPerpPositions()
const [settleMktAddress, setSettleMktAddress] = useState<string>('') const [settleMktAddress, setSettleMktAddress] = useState<string>('')
const { width } = useViewport() const { width } = useViewport()
const showTableView = width ? width > breakpoints.md : false const showTableView = width ? width > breakpoints.md : false
@ -136,8 +134,8 @@ const UnsettledTrades = ({
if (!group) return null if (!group) return null
return mangoAccountAddress && return mangoAccountAddress &&
Object.values(unsettledSpotBalances).flat().concat(unsettledPerpPositions) (Object.values(unsettledSpotBalances)?.length ||
.length ? ( unsettledPerpPositions?.length) ? (
showTableView ? ( showTableView ? (
<Table> <Table>
<thead> <thead>
@ -163,22 +161,22 @@ const UnsettledTrades = ({
<TableMarketName market={market} /> <TableMarketName market={market} />
</Td> </Td>
<Td className="text-right font-mono"> <Td className="text-right font-mono">
<div className="flex justify-end"> <div className="flex flex-wrap justify-end">
{unsettledSpotBalances[mktAddress].base ? ( {unsettledSpotBalances[mktAddress].base ? (
<div> <p>
<FormatNumericValue <FormatNumericValue
value={unsettledSpotBalances[mktAddress].base} value={unsettledSpotBalances[mktAddress].base}
/>{' '} />{' '}
<span className="font-body text-th-fgd-4">{base}</span> <span className="font-body text-th-fgd-4">{base}</span>
</div> </p>
) : null} ) : null}
{unsettledSpotBalances[mktAddress].quote ? ( {unsettledSpotBalances[mktAddress].quote ? (
<div className="ml-4"> <p className="ml-3">
<FormatNumericValue <FormatNumericValue
value={unsettledSpotBalances[mktAddress].quote} value={unsettledSpotBalances[mktAddress].quote}
/>{' '} />{' '}
<span className="font-body text-th-fgd-4">{quote}</span> <span className="font-body text-th-fgd-4">{quote}</span>
</div> </p>
) : null} ) : null}
</div> </div>
</Td> </Td>
@ -212,12 +210,14 @@ const UnsettledTrades = ({
<Td> <Td>
<TableMarketName market={market} /> <TableMarketName market={market} />
</Td> </Td>
<Td className="text-right font-mono"> <Td>
<FormatNumericValue <p className="text-right font-mono">
value={position.getUnsettledPnlUi(market)} <FormatNumericValue
decimals={2} value={position.getUnsettledPnlUi(market)}
/>{' '} decimals={2}
<span className="font-body text-th-fgd-4">USDC</span> />{' '}
<span className="font-body text-th-fgd-4">USDC</span>
</p>
</Td> </Td>
{!isUnownedAccount ? ( {!isUnownedAccount ? (
<Td> <Td>
@ -254,13 +254,13 @@ const UnsettledTrades = ({
> >
<TableMarketName market={market} /> <TableMarketName market={market} />
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<div className="font-mono"> <p className="font-mono text-th-fgd-1">
<FormatNumericValue <FormatNumericValue
value={position.getUnsettledPnlUi(market)} value={position.getUnsettledPnlUi(market)}
decimals={market.baseDecimals} decimals={market.baseDecimals}
/>{' '} />{' '}
<span className="font-body text-th-fgd-4">USDC</span> <span className="font-body text-th-fgd-4">USDC</span>
</div> </p>
{!isUnownedAccount ? ( {!isUnownedAccount ? (
<IconButton <IconButton
onClick={() => handleSettlePerpFunds(market)} onClick={() => handleSettlePerpFunds(market)}
@ -291,22 +291,24 @@ const UnsettledTrades = ({
> >
<TableMarketName market={market} /> <TableMarketName market={market} />
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
{unsettledSpotBalances[mktAddress].base ? ( <div>
<span className="font-mono text-sm"> {unsettledSpotBalances[mktAddress].base ? (
<FormatNumericValue <p className="text-right font-mono text-sm text-th-fgd-1">
value={unsettledSpotBalances[mktAddress].base} <FormatNumericValue
/>{' '} value={unsettledSpotBalances[mktAddress].base}
<span className="font-body text-th-fgd-4">{base}</span> />{' '}
</span> <span className="font-body text-th-fgd-4">{base}</span>
) : null} </p>
{unsettledSpotBalances[mktAddress].quote ? ( ) : null}
<span className="font-mono text-sm"> {unsettledSpotBalances[mktAddress].quote ? (
<FormatNumericValue <p className="text-right font-mono text-sm text-th-fgd-1">
value={unsettledSpotBalances[mktAddress].quote} <FormatNumericValue
/>{' '} value={unsettledSpotBalances[mktAddress].quote}
<span className="font-body text-th-fgd-4">{quote}</span> />{' '}
</span> <span className="font-body text-th-fgd-4">{quote}</span>
) : null} </p>
) : null}
</div>
{!isUnownedAccount ? ( {!isUnownedAccount ? (
<IconButton <IconButton
onClick={() => handleSettleSerumFunds(mktAddress)} onClick={() => handleSettleSerumFunds(mktAddress)}

View File

@ -101,6 +101,7 @@
"return-on-equity": "Return on Equity", "return-on-equity": "Return on Equity",
"rises-to": "rises above", "rises-to": "rises above",
"sells": "Sells", "sells": "Sells",
"settle": "Settle",
"settle-funds": "Settle Funds", "settle-funds": "Settle Funds",
"settle-funds-error": "Failed to settle funds", "settle-funds-error": "Failed to settle funds",
"short": "Short", "short": "Short",
@ -143,6 +144,7 @@
"tweet-position": "Tweet", "tweet-position": "Tweet",
"unrealized-pnl": "Unrealized PnL", "unrealized-pnl": "Unrealized PnL",
"unsettled": "Unsettled", "unsettled": "Unsettled",
"unsettled-balances": "Unsettled Balances",
"volume-alert": "Volume Alert", "volume-alert": "Volume Alert",
"volume-alert-desc": "Play a sound whenever volume exceeds your alert threshold", "volume-alert-desc": "Play a sound whenever volume exceeds your alert threshold",
"warning-init-health": "You have no free collateral", "warning-init-health": "You have no free collateral",

View File

@ -101,6 +101,7 @@
"return-on-equity": "Return on Equity", "return-on-equity": "Return on Equity",
"rises-to": "rises above", "rises-to": "rises above",
"sells": "Sells", "sells": "Sells",
"settle": "Settle",
"settle-funds": "Settle Funds", "settle-funds": "Settle Funds",
"settle-funds-error": "Failed to settle funds", "settle-funds-error": "Failed to settle funds",
"short": "Short", "short": "Short",
@ -143,6 +144,7 @@
"tweet-position": "Tweet", "tweet-position": "Tweet",
"unrealized-pnl": "Unrealized PnL", "unrealized-pnl": "Unrealized PnL",
"unsettled": "Unsettled", "unsettled": "Unsettled",
"unsettled-balances": "Unsettled Balances",
"view-counterparty": "View counterparty {{pk}}", "view-counterparty": "View counterparty {{pk}}",
"volume-alert": "Volume Alert", "volume-alert": "Volume Alert",
"volume-alert-desc": "Play a sound whenever volume exceeds your alert threshold", "volume-alert-desc": "Play a sound whenever volume exceeds your alert threshold",

View File

@ -101,6 +101,7 @@
"return-on-equity": "Retorno sobre o Patrimônio", "return-on-equity": "Retorno sobre o Patrimônio",
"rises-to": "sobe acima de", "rises-to": "sobe acima de",
"sells": "Vende", "sells": "Vende",
"settle": "Liquidar",
"settle-funds": "Liquidar Fundos", "settle-funds": "Liquidar Fundos",
"settle-funds-error": "Falha ao liquidar fundos", "settle-funds-error": "Falha ao liquidar fundos",
"short": "Short", "short": "Short",
@ -143,6 +144,7 @@
"tweet-position": "Tweetar", "tweet-position": "Tweetar",
"unrealized-pnl": "PnL Não Realizado", "unrealized-pnl": "PnL Não Realizado",
"unsettled": "Não Liquidado", "unsettled": "Não Liquidado",
"unsettled-balances": "Unsettled Balances",
"volume-alert": "Alerta de Volume", "volume-alert": "Alerta de Volume",
"volume-alert-desc": "Tocar um som sempre que o volume exceder seu limite de alerta", "volume-alert-desc": "Tocar um som sempre que o volume exceder seu limite de alerta",
"warning-init-health": "You have no free collateral", "warning-init-health": "You have no free collateral",

View File

@ -101,6 +101,7 @@
"return-on-equity": "Return on Equity", "return-on-equity": "Return on Equity",
"rises-to": "rises above", "rises-to": "rises above",
"sells": "Sells", "sells": "Sells",
"settle": "Settle",
"settle-funds": "Settle Funds", "settle-funds": "Settle Funds",
"settle-funds-error": "Failed to settle funds", "settle-funds-error": "Failed to settle funds",
"short": "Short", "short": "Short",
@ -143,6 +144,7 @@
"tweet-position": "Tweet", "tweet-position": "Tweet",
"unrealized-pnl": "Unrealized PnL", "unrealized-pnl": "Unrealized PnL",
"unsettled": "Unsettled", "unsettled": "Unsettled",
"unsettled-balances": "Unsettled Balances",
"view-counterparty": "View counterparty {{pk}}", "view-counterparty": "View counterparty {{pk}}",
"volume-alert": "Volume Alert", "volume-alert": "Volume Alert",
"volume-alert-desc": "Play a sound whenever volume exceeds your alert threshold", "volume-alert-desc": "Play a sound whenever volume exceeds your alert threshold",

View File

@ -101,6 +101,7 @@
"return-on-equity": "股本回报率", "return-on-equity": "股本回报率",
"rises-to": "上涨至", "rises-to": "上涨至",
"sells": "卖单", "sells": "卖单",
"settle": "Settle",
"settle-funds": "结清资金", "settle-funds": "结清资金",
"settle-funds-error": "结清出错", "settle-funds-error": "结清出错",
"short": "做空", "short": "做空",
@ -143,6 +144,7 @@
"tweet-position": "分享至Twitter", "tweet-position": "分享至Twitter",
"unrealized-pnl": "未实现盈亏", "unrealized-pnl": "未实现盈亏",
"unsettled": "未结清", "unsettled": "未结清",
"unsettled-balances": "Unsettled Balances",
"view-counterparty": "查看交易对手 {{pk}}", "view-counterparty": "查看交易对手 {{pk}}",
"volume-alert": "交易量警报", "volume-alert": "交易量警报",
"volume-alert-desc": "交易量超过警报设定时播放声音", "volume-alert-desc": "交易量超过警报设定时播放声音",

View File

@ -101,6 +101,7 @@
"return-on-equity": "股本回報率", "return-on-equity": "股本回報率",
"rises-to": "上漲至", "rises-to": "上漲至",
"sells": "賣單", "sells": "賣單",
"settle": "Settle",
"settle-funds": "結清資金", "settle-funds": "結清資金",
"settle-funds-error": "結清出錯", "settle-funds-error": "結清出錯",
"short": "做空", "short": "做空",
@ -143,6 +144,7 @@
"tweet-position": "分享至Twitter", "tweet-position": "分享至Twitter",
"unrealized-pnl": "未實現盈虧", "unrealized-pnl": "未實現盈虧",
"unsettled": "未結清", "unsettled": "未結清",
"unsettled-balances": "Unsettled Balances",
"view-counterparty": "查看交易對手 {{pk}}", "view-counterparty": "查看交易對手 {{pk}}",
"volume-alert": "交易量警報", "volume-alert": "交易量警報",
"volume-alert-desc": "交易量超過警報設定時播放聲音", "volume-alert-desc": "交易量超過警報設定時播放聲音",