Merge branch 'main' into onboarding-tours

This commit is contained in:
tjshipe 2022-10-04 13:23:29 -04:00 committed by GitHub
commit c0bb9ddcda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 747 additions and 308 deletions

View File

@ -14,6 +14,7 @@ import { LAST_ACCOUNT_KEY } from '../utils/constants'
import { useTranslation } from 'next-i18next'
import { retryFn } from '../utils'
import Loading from './shared/Loading'
import ActionTokenList from './account/ActionTokenList'
const MangoAccountsList = ({
mangoAccount,
@ -22,6 +23,7 @@ const MangoAccountsList = ({
}) => {
const { t } = useTranslation('common')
const mangoAccounts = mangoStore((s) => s.mangoAccounts.accounts)
const actions = mangoStore((s) => s.actions)
const loading = mangoStore((s) => s.mangoAccount.initialLoad)
const [showNewAccountModal, setShowNewAccountModal] = useState(false)
const [, setLastAccountViewed] = useLocalStorageStringState(LAST_ACCOUNT_KEY)
@ -41,6 +43,7 @@ const MangoAccountsList = ({
s.mangoAccount.lastUpdatedAt = new Date().toISOString()
})
setLastAccountViewed(acc.publicKey.toString())
actions.fetchSerumOpenOrders(acc)
} catch (e) {
console.warn('Error selecting account', e)
}
@ -76,7 +79,7 @@ const MangoAccountsList = ({
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Popover.Panel className="absolute top-[13.5px] -right-5 z-10 mr-4 w-56 rounded-md rounded-t-none border border-th-bkg-2 bg-th-bkg-3 p-4 text-th-fgd-3">
<Popover.Panel className="absolute top-[13.5px] -right-5 z-20 mr-4 w-56 rounded-md rounded-t-none border border-th-bkg-2 bg-th-bkg-3 p-4 text-th-fgd-3">
{loading ? (
<Loading />
) : mangoAccounts.length ? (
@ -84,7 +87,7 @@ const MangoAccountsList = ({
<div key={acc.publicKey.toString()}>
<button
onClick={() => handleSelectMangoAccount(acc)}
className="mb-3 flex w-full items-center justify-between border-b border-th-bkg-4 pb-3 hover:text-th-fgd-1"
className="default-transition mb-3 flex w-full items-center justify-between border-b border-th-bkg-4 pb-3 hover:text-th-fgd-1"
>
{acc.name}
{acc.publicKey.toString() ===

View File

@ -4,7 +4,7 @@ import {
} from '@blockworks-foundation/mango-v4'
import { useTranslation } from 'next-i18next'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { useEffect, useMemo, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import AccountActions from './AccountActions'
import DepositModal from '../modals/DepositModal'
import WithdrawModal from '../modals/WithdrawModal'
@ -138,6 +138,19 @@ const AccountPage = () => {
return mangoAccount ? mangoAccount.getHealthRatioUi(HealthType.maint) : 0
}, [mangoAccount])
const handleChartToShow = (chartName: string) => {
if (chartName === 'cumulative-interest-value') {
if (interestTotalValue > 1 || interestTotalValue < -1) {
setChartToShow(chartName)
}
}
if (chartName === 'pnl') {
if (performanceData.length > 4) {
setChartToShow(chartName)
}
}
}
return !chartToShow ? (
<>
<div className="flex flex-wrap items-center justify-between border-b-0 border-th-bkg-3 px-6 pt-3 pb-0 md:border-b md:pb-3">
@ -233,7 +246,7 @@ const AccountPage = () => {
</div>
</div>
<div className="grid grid-cols-4 border-b border-th-bkg-3">
<div className="col-span-4 border-t border-th-bkg-3 py-3 pl-6 md:col-span-1 md:col-span-2 md:border-l md:border-t-0 lg:col-span-1">
<div className="col-span-4 flex border-t border-th-bkg-3 py-3 pl-6 md:col-span-1 md:col-span-2 md:border-l md:border-t-0 lg:col-span-1">
<div id="account-step-four">
<Tooltip
maxWidth="20rem"
@ -276,7 +289,7 @@ const AccountPage = () => {
</p>
</div>
</div>
<div className="col-span-4 border-t border-th-bkg-3 py-3 pl-6 md:col-span-1 md:col-span-2 md:border-l md:border-t-0 lg:col-span-1">
<div className="col-span-4 flex border-t border-th-bkg-3 py-3 pl-6 md:col-span-1 md:col-span-2 md:border-l md:border-t-0 lg:col-span-1">
<div id="account-step-five">
<Tooltip
content="The amount of capital you have to trade or borrow against. When your free collateral reaches $0 you won't be able to make withdrawals."
@ -299,51 +312,59 @@ const AccountPage = () => {
</p>
</div>
</div>
<div className="col-span-4 flex items-center justify-between border-t border-th-bkg-3 py-3 px-6 md:col-span-2 md:col-span-2 md:border-l lg:col-span-1 lg:border-t-0">
<div id="account-step-six">
<Tooltip
content="The amount your account has made or lost."
placement="bottom-start"
>
<p className="tooltip-underline text-th-fgd-3">{t('pnl')}</p>
</Tooltip>
<p className="mt-1 text-2xl font-bold text-th-fgd-1">
{formatFixedDecimals(accountPnl, true)}
</p>
</div>
{performanceData.length > 4 ? (
<IconButton
onClick={() => setChartToShow('pnl')}
size={!isMobile ? 'small' : 'medium'}
>
<ChevronRightIcon className="h-5 w-5" />
</IconButton>
) : null}
</div>
<div className="col-span-4 flex items-center justify-between border-t border-th-bkg-3 py-3 pl-6 md:col-span-1 md:col-span-2 md:border-l lg:col-span-1 lg:border-t-0">
<div id="account-step-seven">
<Tooltip
content="The value of interest earned (deposits) minus interest paid (borrows)."
maxWidth="20rem"
placement="bottom-end"
>
<p className="tooltip-underline text-th-fgd-3">
{t('total-interest-value')}
<button
className={`col-span-4 border-t border-th-bkg-3 py-3 px-6 md:col-span-2 md:col-span-2 md:border-l lg:col-span-1 lg:border-t-0 ${
performanceData.length > 4
? 'default-transition cursor-pointer md:hover:bg-th-bkg-2'
: 'cursor-default'
}`}
onClick={() => handleChartToShow('pnl')}
>
<div className="flex items-center justify-between">
<div id="account-step-six">
<Tooltip
content="The amount your account has made or lost."
placement="bottom-start"
>
<p className="tooltip-underline text-th-fgd-3">{t('pnl')}</p>
</Tooltip>
<p className="mt-1 text-2xl font-bold text-th-fgd-1">
{formatFixedDecimals(accountPnl, true)}
</p>
</Tooltip>
<p className="mt-1 text-2xl font-bold text-th-fgd-1">
{formatFixedDecimals(interestTotalValue, true)}
</p>
</div>
{performanceData.length > 4 ? (
<ChevronRightIcon className="h-6 w-6" />
) : null}
</div>
{interestTotalValue > 1 || interestTotalValue < -1 ? (
<IconButton
onClick={() => setChartToShow('cumulative-interest-value')}
size={!isMobile ? 'small' : 'medium'}
>
<ChevronRightIcon className="h-5 w-5" />
</IconButton>
) : null}
</div>
</button>
<button
className={`col-span-4 border-t border-th-bkg-3 py-3 pl-6 text-left md:col-span-1 md:col-span-2 md:border-l lg:col-span-1 lg:border-t-0 ${
interestTotalValue > 1 || interestTotalValue < -1
? 'default-transition cursor-pointer md:hover:bg-th-bkg-2'
: 'cursor-default'
}`}
onClick={() => handleChartToShow('cumulative-interest-value')}
>
<div className="flex items-center justify-between">
<div id="account-step-seven">
<Tooltip
content="The value of interest earned (deposits) minus interest paid (borrows)."
maxWidth="20rem"
placement="bottom-end"
>
<p className="tooltip-underline text-th-fgd-3">
{t('total-interest-value')}
</p>
</Tooltip>
<p className="mt-1 text-2xl font-bold text-th-fgd-1">
{formatFixedDecimals(interestTotalValue, true)}
</p>
</div>
{interestTotalValue > 1 || interestTotalValue < -1 ? (
<ChevronRightIcon className="h-6 w-6" />
) : null}
</div>
</button>
</div>
<AccountTabs />
{showDepositModal ? (

View File

@ -18,7 +18,7 @@ const TabButtons: FunctionComponent<TabButtonsProps> = ({
rounded = false,
fillWidth = false,
}) => {
const { t } = useTranslation(['common', 'swap'])
const { t } = useTranslation(['common', 'swap', 'trade'])
return (
<div
@ -29,7 +29,7 @@ const TabButtons: FunctionComponent<TabButtonsProps> = ({
{values.map(([label, count], i) => (
<div className={fillWidth ? 'flex-1' : ''} key={label + i}>
<button
className={`default-transition flex h-12 w-full items-center justify-center px-6 font-bold ${
className={`default-transition flex h-12 w-full items-center justify-center px-4 font-bold md:px-6 ${
rounded ? 'rounded-md' : 'rounded-none'
} ${showBorders ? 'border-r border-th-bkg-3' : ''} ${
label === activeValue
@ -44,7 +44,7 @@ const TabButtons: FunctionComponent<TabButtonsProps> = ({
<div
className={`ml-1.5 rounded ${
label === activeValue ? 'bg-th-bkg-4' : 'bg-th-bkg-3'
} px-1.5 font-mono text-xxs`}
} px-1.5 font-mono text-xxs text-th-fgd-2`}
>
{count}
</div>

View File

@ -135,7 +135,7 @@ const OraclePrice = () => {
}
const AdvancedMarketHeader = () => {
const { t } = useTranslation('common')
const { t } = useTranslation(['common', 'trade'])
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data)
@ -164,7 +164,7 @@ const AdvancedMarketHeader = () => {
</div>
</div>
<div id="trade-step-two" className="ml-6 flex-col">
<div className="text-xs text-th-fgd-4">{t('oracle-price')}</div>
<div className="text-xs text-th-fgd-4">{t('trade:oracle-price')}</div>
<OraclePrice />
</div>
<div className="ml-6 flex-col">

View File

@ -18,6 +18,9 @@ import NumberFormat, {
import { notify } from 'utils/notifications'
import SpotSlider from './SpotSlider'
import { calculateMarketPrice } from 'utils/tradeForm'
import Image from 'next/image'
import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid'
import Loading from '@components/shared/Loading'
const TABS: [string, number][] = [
['Limit', 0],
@ -25,20 +28,40 @@ const TABS: [string, number][] = [
]
const AdvancedTradeForm = () => {
const { t } = useTranslation('common')
const { t } = useTranslation(['common', 'trade'])
const set = mangoStore.getState().set
const tradeForm = mangoStore((s) => s.tradeForm)
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
const [useMargin, setUseMargin] = useState(true)
const [placingOrder, setPlacingOrder] = useState(false)
const baseSymbol = useMemo(() => {
return selectedMarket?.name.split('/')[0]
}, [selectedMarket])
const baseLogoURI = useMemo(() => {
if (!baseSymbol || !jupiterTokens.length) return ''
const token = jupiterTokens.find((t) => t.symbol === baseSymbol)
if (token) {
return token.logoURI
}
return ''
}, [baseSymbol, jupiterTokens])
const quoteSymbol = useMemo(() => {
return selectedMarket?.name.split('/')[1]
}, [selectedMarket])
const quoteLogoURI = useMemo(() => {
if (!quoteSymbol || !jupiterTokens.length) return ''
const token = jupiterTokens.find((t) => t.symbol === quoteSymbol)
if (token) {
return token.logoURI
}
return ''
}, [quoteSymbol, jupiterTokens])
const setTradeType = useCallback(
(tradeType: 'Limit' | 'Market') => {
set((s) => {
@ -66,7 +89,6 @@ const AdvancedTradeForm = () => {
const handleBaseSizeChange = useCallback(
(e: NumberFormatValues, info: SourceInfo) => {
if (info.source !== 'event') return
console.log('ho')
set((s) => {
s.tradeForm.baseSize = e.value
@ -84,7 +106,6 @@ const AdvancedTradeForm = () => {
const handleQuoteSizeChange = useCallback(
(e: NumberFormatValues, info: SourceInfo) => {
if (info.source !== 'event') return
console.log('hi')
set((s) => {
s.tradeForm.quoteSize = e.value
@ -155,7 +176,7 @@ const AdvancedTradeForm = () => {
const selectedMarket = mangoStore.getState().selectedMarket.current
if (!group || !mangoAccount) return
setPlacingOrder(true)
try {
const orderType = tradeForm.ioc
? Serum3OrderType.immediateOrCancel
@ -197,6 +218,8 @@ const AdvancedTradeForm = () => {
type: 'error',
})
console.error('Place trade error:', e)
} finally {
setPlacingOrder(false)
}
}, [t])
@ -255,7 +278,7 @@ const AdvancedTradeForm = () => {
{tradeForm.tradeType === 'Limit' ? (
<>
<div className="mb-2 mt-4 flex items-center justify-between">
<p className="text-xs text-th-fgd-3">Limit Price</p>
<p className="text-xs text-th-fgd-3">{t('trade:limit-price')}</p>
</div>
<div className="default-transition flex items-center rounded-md border border-th-bkg-4 bg-th-bkg-1 p-2 text-xs font-bold text-th-fgd-1 md:hover:border-th-fgd-4 md:hover:bg-th-bkg-2 lg:text-base">
<NumberFormat
@ -278,10 +301,21 @@ const AdvancedTradeForm = () => {
</>
) : null}
<div className="my-2 flex items-center justify-between">
<p className="text-xs text-th-fgd-3">{t('amount')}</p>
<p className="text-xs text-th-fgd-3">{t('trade:amount')}</p>
</div>
<div className="flex flex-col">
<div className="default-transition flex items-center rounded-md border border-th-bkg-4 bg-th-bkg-1 p-2 text-xs font-bold text-th-fgd-1 md:hover:border-th-fgd-4 md:hover:bg-th-bkg-2 lg:text-base">
<div className="default-transition flex items-center rounded-md rounded-b-none border border-th-bkg-4 bg-th-bkg-1 p-2 text-xs font-bold text-th-fgd-1 md:hover:z-10 md:hover:border-th-fgd-4 md:hover:bg-th-bkg-2 lg:text-base">
{baseLogoURI ? (
<Image
className="rounded-full"
alt=""
width="24"
height="24"
src={baseLogoURI}
/>
) : (
<QuestionMarkCircleIcon className="h-6 w-6 text-th-fgd-3" />
)}
<NumberFormat
inputMode="decimal"
thousandSeparator=","
@ -290,7 +324,7 @@ const AdvancedTradeForm = () => {
decimalScale={6}
name="amountIn"
id="amountIn"
className="w-full bg-transparent font-mono focus:outline-none"
className="ml-2 w-full bg-transparent font-mono focus:outline-none"
placeholder="0.00"
value={tradeForm.baseSize}
onValueChange={handleBaseSizeChange}
@ -299,7 +333,18 @@ const AdvancedTradeForm = () => {
{baseSymbol}
</div>
</div>
<div className="default-transition mt-1 flex items-center rounded-md border border-th-bkg-4 bg-th-bkg-1 p-2 text-xs font-bold text-th-fgd-1 md:hover:border-th-fgd-4 md:hover:bg-th-bkg-2 lg:text-base">
<div className="default-transition -mt-[1px] flex items-center rounded-md rounded-t-none border border-th-bkg-4 bg-th-bkg-1 p-2 text-xs font-bold text-th-fgd-1 md:hover:border-th-fgd-4 md:hover:bg-th-bkg-2 lg:text-base">
{quoteLogoURI ? (
<Image
className="rounded-full"
alt=""
width="24"
height="24"
src={quoteLogoURI}
/>
) : (
<QuestionMarkCircleIcon className="h-6 w-6 text-th-fgd-3" />
)}
<NumberFormat
inputMode="decimal"
thousandSeparator=","
@ -308,7 +353,7 @@ const AdvancedTradeForm = () => {
decimalScale={6}
name="amountIn"
id="amountIn"
className="w-full bg-transparent font-mono focus:outline-none"
className="ml-2 w-full bg-transparent font-mono focus:outline-none"
placeholder="0.00"
value={tradeForm.quoteSize}
onValueChange={handleQuoteSizeChange}
@ -330,13 +375,13 @@ const AdvancedTradeForm = () => {
className="hidden md:block"
delay={250}
placement="left"
content={t('tooltip-post')}
content={t('trade:tooltip-post')}
>
<Checkbox
checked={tradeForm.postOnly}
onChange={(e) => handlePostOnlyChange(e.target.checked)}
>
Post
{t('trade:post')}
</Checkbox>
</Tooltip>
</div>
@ -344,8 +389,8 @@ const AdvancedTradeForm = () => {
<Tooltip
className="hidden md:block"
delay={250}
placement="top"
content={t('tooltip-ioc')}
placement="left"
content={t('trade:tooltip-ioc')}
>
<div className="flex items-center text-xs text-th-fgd-3">
<Checkbox
@ -363,13 +408,13 @@ const AdvancedTradeForm = () => {
<Tooltip
delay={250}
placement="left"
content={t('tooltip-enable-margin')}
content={t('trade:tooltip-enable-margin')}
>
<Checkbox
checked={useMargin}
onChange={(e) => setUseMargin(e.target.checked)}
>
{t('margin')}
{t('trade:margin')}
</Checkbox>
</Tooltip>
</div>
@ -385,7 +430,16 @@ const AdvancedTradeForm = () => {
disabled={false}
size="large"
>
<span className="capitalize">Place {tradeForm.side} Order</span>
{!placingOrder ? (
<span className="capitalize">
{t('trade:place-order', { side: tradeForm.side })}
</span>
) : (
<div className="flex items-center space-x-2">
<Loading />
<span>{t('trade:placing-order')}</span>
</div>
)}
</Button>
</div>
</div>

View File

@ -1,5 +1,6 @@
import { Serum3Side } from '@blockworks-foundation/mango-v4'
import { IconButton } from '@components/shared/Button'
import Loading from '@components/shared/Loading'
import SideBadge from '@components/shared/SideBadge'
import Tooltip from '@components/shared/Tooltip'
import { LinkIcon, TrashIcon } from '@heroicons/react/20/solid'
@ -7,17 +8,22 @@ import { Order } from '@project-serum/serum/lib/market'
import { useWallet } from '@solana/wallet-adapter-react'
import { PublicKey } from '@solana/web3.js'
import mangoStore from '@store/mangoStore'
import { useViewport } from 'hooks/useViewport'
import { useTranslation } from 'next-i18next'
import { useCallback } from 'react'
import { useCallback, useState } from 'react'
import { notify } from 'utils/notifications'
import { formatFixedDecimals } from 'utils/numbers'
import { formatFixedDecimals, getDecimalCount } from 'utils/numbers'
import { breakpoints } from 'utils/theme'
import MarketLogos from './MarketLogos'
const OpenOrders = () => {
const { t } = useTranslation('common')
const { t } = useTranslation(['common', 'trade'])
const { connected } = useWallet()
const openOrders = mangoStore((s) => s.mangoAccount.openOrders)
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
const [cancelId, setCancelId] = useState<string>('')
const { width } = useViewport()
const showTableView = width ? width > breakpoints.md : false
const handleCancelOrder = useCallback(
async (o: Order) => {
@ -28,7 +34,7 @@ const OpenOrders = () => {
const actions = mangoStore.getState().actions
if (!group || !mangoAccount) return
setCancelId(o.orderId.toString())
try {
const tx = await client.serum3CancelOrder(
group,
@ -46,11 +52,13 @@ const OpenOrders = () => {
} catch (e: any) {
console.error('Error canceling', e)
notify({
title: t('order-error'),
title: t('trade:cancel-order-error'),
description: e.message,
txid: e.txid,
type: 'error',
})
} finally {
setCancelId('')
}
},
[t]
@ -58,93 +66,184 @@ const OpenOrders = () => {
return connected ? (
Object.values(openOrders).flat().length ? (
<table>
<thead>
<tr>
<th className="text-left">{t('market')}</th>
<th className="text-right">{t('side')}</th>
<th className="text-right">{t('size')}</th>
<th className="text-right">{t('price')}</th>
<th className="text-right">{t('value')}</th>
<th className="text-right"></th>
</tr>
</thead>
<tbody>
{Object.entries(openOrders)
.map(([marketPk, orders]) => {
return orders.map((o) => {
const group = mangoStore.getState().group
const market = group?.getSerum3MarketByPk(
new PublicKey(marketPk)
)
let baseLogoURI = ''
let quoteLogoURI = ''
const baseSymbol = group?.getFirstBankByTokenIndex(
market!.baseTokenIndex
).name
const quoteSymbol = group?.getFirstBankByTokenIndex(
market!.quoteTokenIndex
).name
if (jupiterTokens.length) {
baseLogoURI = jupiterTokens.find(
(t) => t.symbol === baseSymbol
)!.logoURI
quoteLogoURI = jupiterTokens.find(
(t) => t.symbol === quoteSymbol
)!.logoURI
}
return (
<tr key={`${o.side}${o.size}${o.price}`} className="my-1 p-2">
<td>
<div className="flex items-center">
<MarketLogos
baseURI={baseLogoURI}
quoteURI={quoteLogoURI}
/>
{market?.name}
</div>
</td>
<td className="text-right">
<SideBadge side={o.side} />
</td>
<td className="text-right">{o.size}</td>
<td className="text-right">
<span>
{o.price}{' '}
<span className="text-th-fgd-4">{quoteSymbol}</span>
</span>
</td>
<td className="text-right">
{formatFixedDecimals(o.size * o.price, true)}
</td>
<td>
<div className="flex justify-end">
<Tooltip content={t('cancel')}>
<IconButton
onClick={() => handleCancelOrder(o)}
size="small"
>
<TrashIcon className="h-4 w-4" />
</IconButton>
</Tooltip>
</div>
</td>
</tr>
)
showTableView ? (
<table>
<thead>
<tr>
<th className="text-left">{t('market')}</th>
<th className="text-right">{t('trade:side')}</th>
<th className="text-right">{t('trade:size')}</th>
<th className="text-right">{t('price')}</th>
<th className="text-right">{t('value')}</th>
<th className="text-right"></th>
</tr>
</thead>
<tbody>
{Object.entries(openOrders)
.map(([marketPk, orders]) => {
return orders.map((o) => {
const group = mangoStore.getState().group
const market = group?.getSerum3MarketByPk(
new PublicKey(marketPk)
)
let baseLogoURI = ''
let quoteLogoURI = ''
const baseSymbol = group?.getFirstBankByTokenIndex(
market!.baseTokenIndex
).name
const quoteSymbol = group?.getFirstBankByTokenIndex(
market!.quoteTokenIndex
).name
if (jupiterTokens.length) {
baseLogoURI = jupiterTokens.find(
(t) => t.symbol === baseSymbol
)!.logoURI
quoteLogoURI = jupiterTokens.find(
(t) => t.symbol === quoteSymbol
)!.logoURI
}
return (
<tr
key={`${o.side}${o.size}${o.price}`}
className="my-1 p-2"
>
<td>
<div className="flex items-center">
<MarketLogos
baseURI={baseLogoURI}
quoteURI={quoteLogoURI}
/>
{market?.name}
</div>
</td>
<td className="text-right">
<SideBadge side={o.side} />
</td>
<td className="text-right font-mono">
{o.size.toLocaleString(undefined, {
maximumFractionDigits: getDecimalCount(o.size),
})}
</td>
<td className="text-right">
<span className="font-mono">
{o.price.toLocaleString(undefined, {
maximumFractionDigits: getDecimalCount(o.price),
})}{' '}
<span className="font-body tracking-wide text-th-fgd-4">
{quoteSymbol}
</span>
</span>
</td>
<td className="text-right font-mono">
{formatFixedDecimals(o.size * o.price, true)}
</td>
<td>
<div className="flex justify-end">
<Tooltip content={t('cancel')}>
<IconButton
disabled={cancelId === o.orderId.toString()}
onClick={() => handleCancelOrder(o)}
size="small"
>
{cancelId === o.orderId.toString() ? (
<Loading className="h-4 w-4" />
) : (
<TrashIcon className="h-4 w-4" />
)}
</IconButton>
</Tooltip>
</div>
</td>
</tr>
)
})
})
.flat()}
</tbody>
</table>
) : (
<div className="pb-20">
{Object.entries(openOrders).map(([marketPk, orders]) => {
return orders.map((o) => {
const group = mangoStore.getState().group
const market = group?.getSerum3MarketByPk(new PublicKey(marketPk))
let baseLogoURI = ''
let quoteLogoURI = ''
const baseSymbol = group?.getFirstBankByTokenIndex(
market!.baseTokenIndex
).name
const quoteSymbol = group?.getFirstBankByTokenIndex(
market!.quoteTokenIndex
).name
if (jupiterTokens.length) {
baseLogoURI = jupiterTokens.find(
(t) => t.symbol === baseSymbol
)!.logoURI
quoteLogoURI = jupiterTokens.find(
(t) => t.symbol === quoteSymbol
)!.logoURI
}
return (
<div
className="flex items-center justify-between border-b border-th-bkg-3 p-4"
key={`${o.side}${o.size}${o.price}`}
>
<div className="flex items-center">
<MarketLogos
baseURI={baseLogoURI}
quoteURI={quoteLogoURI}
/>
<div>
<p className="text-sm text-th-fgd-1">{market?.name}</p>
<span
className={`capitalize ${
o.side === 'buy' ? 'text-th-green' : 'text-th-red'
}`}
>
{o.side}
</span>{' '}
<span className="font-mono">
{o.size.toLocaleString(undefined, {
maximumFractionDigits: getDecimalCount(o.size),
})}
</span>{' '}
<span className="text-th-fgd-4">at</span>{' '}
<span className="font-mono">
{o.price.toLocaleString(undefined, {
maximumFractionDigits: getDecimalCount(o.price),
})}
</span>{' '}
<span className="text-th-fgd-4">{quoteSymbol}</span>
</div>
</div>
<div className="flex items-center space-x-3 pl-4">
<span>{formatFixedDecimals(o.size * o.price, true)}</span>
<IconButton
disabled={cancelId === o.orderId.toString()}
onClick={() => handleCancelOrder(o)}
>
{cancelId === o.orderId.toString() ? (
<Loading className="h-4 w-4" />
) : (
<TrashIcon className="h-4 w-4" />
)}
</IconButton>
</div>
</div>
)
})
.flat()}
</tbody>
</table>
})}
</div>
)
) : (
<div className="flex flex-col items-center p-8">
<p>No open orders...</p>
<p>{t('trade:no-orders')}</p>
</div>
)
) : (
<div className="flex flex-col items-center p-8">
<LinkIcon className="mb-2 h-6 w-6 text-th-fgd-4" />
<p>Connect to view your open orders</p>
<p>{t('trade:connect-orders')}</p>
</div>
)
}

View File

@ -156,7 +156,7 @@ const groupBy = (
const depth = 40
const Orderbook = () => {
const { t } = useTranslation('common')
const { t } = useTranslation(['common', 'trade'])
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
// const [openOrderPrices, setOpenOrderPrices] = useState<any[]>([])
@ -382,7 +382,7 @@ const Orderbook = () => {
<div className="flex items-center justify-between border-b border-th-bkg-3 px-4 py-2">
<div id="trade-step-three" className="flex items-center space-x-2">
<Tooltip
content={showBuys ? 'Hide Buys' : 'Show Buys'}
content={showBuys ? t('trade:hide-bids') : t('trade:show-bids')}
placement="top"
>
<button
@ -396,7 +396,7 @@ const Orderbook = () => {
</button>
</Tooltip>
<Tooltip
content={showSells ? 'Hide Sells' : 'Show Sells'}
content={showSells ? t('trade:hide-asks') : t('trade:show-asks')}
placement="top"
>
<button
@ -412,7 +412,7 @@ const Orderbook = () => {
</div>
{serum3MarketExternal ? (
<div id="trade-step-four">
<Tooltip content="Grouping" placement="top">
<Tooltip content={t('trade:grouping')} placement="top">
<GroupSize
tickSize={serum3MarketExternal.tickSize}
onChange={onGroupSizeChange}
@ -423,7 +423,7 @@ const Orderbook = () => {
) : null}
</div>
<div className="grid grid-cols-2 px-4 pt-2 pb-1 text-xxs text-th-fgd-4">
<div className="col-span-1 text-right">{t('size')}</div>
<div className="col-span-1 text-right">{t('trade:size')}</div>
<div className="col-span-1 text-right">{t('price')}</div>
</div>
<div
@ -465,7 +465,7 @@ const Orderbook = () => {
id="trade-step-nine"
>
<div className="col-span-1 flex justify-between">
<div className="text-xxs">{t('spread')}</div>
<div className="text-xxs">{t('trade:spread')}</div>
<div className="font-mono">
{orderbookData?.spreadPercentage.toFixed(2)}%
</div>

View File

@ -4,12 +4,12 @@ import Orderbook from './Orderbook'
import RecentTrades from './RecentTrades'
const TABS: [string, number][] = [
['book', 0],
['trades', 0],
['trade:book', 0],
['trade:trades', 0],
]
const OrderbookAndTrades = () => {
const [activeTab, setActiveTab] = useState('book')
const [activeTab, setActiveTab] = useState('trade:book')
return (
<div className="hide-scroll h-full">
<div className="border-b border-r border-th-bkg-3">
@ -20,11 +20,17 @@ const OrderbookAndTrades = () => {
fillWidth
/>
</div>
<div className={`h-full ${activeTab === 'book' ? 'visible' : 'hidden'}`}>
<div
className={`h-full ${
activeTab === 'trade:book' ? 'visible' : 'hidden'
}`}
>
<Orderbook />
</div>
<div
className={`h-full ${activeTab === 'trades' ? 'visible' : 'hidden'}`}
className={`h-full ${
activeTab === 'trade:trades' ? 'visible' : 'hidden'
}`}
>
<RecentTrades />
</div>

View File

@ -8,7 +8,7 @@ import { ChartTradeType } from 'types'
import { useTranslation } from 'next-i18next'
const RecentTrades = () => {
const { t } = useTranslation('common')
const { t } = useTranslation(['common', 'trade'])
const [trades, setTrades] = useState<any[]>([])
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
const selectedMarketPk = selectedMarket?.serumMarketExternal.toBase58()
@ -60,11 +60,11 @@ const RecentTrades = () => {
}
}, 5000)
return (
<div className="h-full overflow-y-scroll ">
<div className="thin-scroll h-full overflow-y-scroll">
<div className={`mb-1 grid grid-cols-3 px-4 pt-2 text-xxs text-th-fgd-4`}>
<div className="text-right">{`${t('price')} (${quoteSymbol})`} </div>
<div className={`text-right`}>
{t('size')} ({baseSymbol})
{t('trade:size')} ({baseSymbol})
</div>
<div className={`text-right`}>{t('time')}</div>
</div>

View File

@ -1,16 +1,20 @@
import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid'
import mangoStore from '@store/mangoStore'
import { useViewport } from 'hooks/useViewport'
import { useTranslation } from 'next-i18next'
import Image from 'next/image'
import { useMemo } from 'react'
import { formatDecimal } from 'utils/numbers'
import { breakpoints } from 'utils/theme'
const Balances = () => {
const { t } = useTranslation('common')
const { t } = useTranslation(['common', 'trade'])
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
const spotBalances = mangoStore((s) => s.mangoAccount.spotBalances)
const group = mangoStore((s) => s.group)
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
const { width } = useViewport()
const showTableView = width ? width > breakpoints.md : false
const banks = useMemo(() => {
if (group) {
@ -41,14 +45,14 @@ const Balances = () => {
return []
}, [group, mangoAccount])
return (
return showTableView ? (
<table className="min-w-full">
<thead>
<tr>
<th className="bg-th-bkg-1 text-left">{t('token')}</th>
<th className="bg-th-bkg-1 text-right">{t('balance')}</th>
<th className="bg-th-bkg-1 text-right">{t('in-orders')}</th>
<th className="bg-th-bkg-1 text-right">{t('unsettled')}</th>
<th className="bg-th-bkg-1 text-right">{t('trade:in-orders')}</th>
<th className="bg-th-bkg-1 text-right">{t('trade:unsettled')}</th>
</tr>
</thead>
<tbody>
@ -97,6 +101,61 @@ const Balances = () => {
})}
</tbody>
</table>
) : (
<>
{banks.map(({ key, value }) => {
const bank = value[0]
let logoURI
if (jupiterTokens.length) {
logoURI = jupiterTokens.find(
(t) => t.address === bank.mint.toString()
)!.logoURI
}
return (
<div
className="flex items-center justify-between border-b border-th-bkg-3 p-4"
key={key}
>
<div className="flex items-center">
<div className="mr-2.5 flex flex-shrink-0 items-center">
{logoURI ? (
<Image alt="" width="20" height="20" src={logoURI} />
) : (
<QuestionMarkCircleIcon className="h-7 w-7 text-th-fgd-3" />
)}
</div>
<span>{bank.name}</span>
</div>
<div className="text-right">
<p className="mb-0.5 font-mono text-sm text-th-fgd-1">
{mangoAccount
? formatDecimal(
mangoAccount.getTokenBalanceUi(bank),
bank.mintDecimals
)
: 0}
</p>
<div className="flex space-x-3">
<p className="text-xs text-th-fgd-4">
{t('trade:in-orders')}:{' '}
<span className="font-mono text-th-fgd-3">
{spotBalances[bank.mint.toString()]?.inOrders || 0.0}
</span>
</p>
<p className="text-xs text-th-fgd-4">
{t('trade:unsettled')}:{' '}
<span className="font-mono text-th-fgd-3">
{spotBalances[bank.mint.toString()]?.unsettled || 0.0}
</span>
</p>
</div>
</div>
</div>
)
})}
</>
)
}

View File

@ -4,18 +4,59 @@ import OpenOrders from './OpenOrders'
import Balances from './TradeBalances'
import UnsettledTrades from './UnsettledTrades'
import mangoStore from '@store/mangoStore'
import { toUiDecimals } from '@blockworks-foundation/mango-v4'
const TradeInfoTabs = () => {
const [selectedTab, setSelectedTab] = useState('Balances')
const [selectedTab, setSelectedTab] = useState('balances')
const openOrders = mangoStore((s) => s.mangoAccount.openOrders)
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
const openOrdersAccounts =
mangoStore.getState().mangoAccount.openOrderAccounts
const group = mangoStore((s) => s.group)
const unsettledSpotBalances = useMemo(() => {
if (!group || !mangoAccount || !openOrdersAccounts) return {}
const unsettledBalances: Record<string, { base: number; quote: number }> =
{}
mangoAccount.serum3Active().forEach((serumMarket) => {
const market = group.getSerum3MarketByIndex(serumMarket.marketIndex)!
const openOrdersAccForMkt = openOrdersAccounts.find((oo) =>
oo.market.equals(market.serumMarketExternal)
)
if (openOrdersAccForMkt) {
const baseTokenUnsettled = toUiDecimals(
openOrdersAccForMkt!.baseTokenFree.toNumber(),
group.getFirstBankByTokenIndex(serumMarket.baseTokenIndex)
.mintDecimals
)
const quoteTokenUnsettled = toUiDecimals(
openOrdersAccForMkt!.quoteTokenFree
// @ts-ignore
.add(openOrdersAccForMkt['referrerRebatesAccrued'])
.toNumber(),
group.getFirstBankByTokenIndex(serumMarket.quoteTokenIndex)
.mintDecimals
)
unsettledBalances[market.serumMarketExternal.toString()] = {
base: baseTokenUnsettled,
quote: quoteTokenUnsettled,
}
}
})
const filtered = Object.entries(unsettledBalances).filter(
([_mkt, balance]) => balance.base > 0 || balance.quote > 0
)
return Object.fromEntries(filtered)!
}, [mangoAccount, group, openOrdersAccounts])
const tabsWithCount: [string, number][] = useMemo(() => {
return [
['Balances', 0],
['Orders', Object.values(openOrders).flat().length],
['Unsettled', 0],
['balances', 0],
['trade:orders', Object.values(openOrders).flat().length],
['trade:unsettled', Object.values(unsettledSpotBalances).flat().length],
]
}, [openOrders])
}, [openOrders, mangoAccount])
return (
<div className="hide-scroll h-full overflow-y-scroll">
@ -27,9 +68,11 @@ const TradeInfoTabs = () => {
showBorders
/>
</div>
{selectedTab === 'Balances' ? <Balances /> : null}
{selectedTab === 'Orders' ? <OpenOrders /> : null}
{selectedTab === 'Unsettled' ? <UnsettledTrades /> : null}
{selectedTab === 'balances' ? <Balances /> : null}
{selectedTab === 'trade:orders' ? <OpenOrders /> : null}
{selectedTab === 'trade:unsettled' ? (
<UnsettledTrades unsettledSpotBalances={unsettledSpotBalances} />
) : null}
</div>
)
}

View File

@ -1,50 +1,28 @@
import mangoStore from '@store/mangoStore'
import { useTranslation } from 'next-i18next'
import { useCallback, useMemo } from 'react'
import { useCallback, useState } from 'react'
import { PublicKey } from '@solana/web3.js'
import { toUiDecimals } from '@blockworks-foundation/mango-v4'
import Button from '@components/shared/Button'
import { IconButton } from '@components/shared/Button'
import { notify } from 'utils/notifications'
import { useWallet } from '@solana/wallet-adapter-react'
import { CheckIcon, LinkIcon } from '@heroicons/react/20/solid'
import Tooltip from '@components/shared/Tooltip'
import Loading from '@components/shared/Loading'
import { useViewport } from 'hooks/useViewport'
import { breakpoints } from 'utils/theme'
const UnsettledTrades = () => {
const { t } = useTranslation('common')
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
const openOrdersAccounts =
mangoStore.getState().mangoAccount.openOrderAccounts
const UnsettledTrades = ({
unsettledSpotBalances,
}: {
unsettledSpotBalances: any
}) => {
const { t } = useTranslation(['common', 'trade'])
const { connected } = useWallet()
const group = mangoStore((s) => s.group)
// const jupiterTokens = mangoStore((s) => s.jupiterTokens)
const unsettledSpotBalances = useMemo(() => {
if (!group || !mangoAccount) return {}
const unsettledBalances: Record<string, { base: number; quote: number }> =
{}
mangoAccount.serum3Active().forEach((serumMarket) => {
const market = group.getSerum3MarketByIndex(serumMarket.marketIndex)!
const openOrdersAccForMkt = openOrdersAccounts.find((oo) =>
oo.market.equals(market.serumMarketExternal)
)
const baseTokenUnsettled = toUiDecimals(
openOrdersAccForMkt!.baseTokenFree.toNumber(),
group.getFirstBankByTokenIndex(serumMarket.baseTokenIndex).mintDecimals
)
const quoteTokenUnsettled = toUiDecimals(
openOrdersAccForMkt!.quoteTokenFree
// @ts-ignore
.add(openOrdersAccForMkt['referrerRebatesAccrued'])
.toNumber(),
group.getFirstBankByTokenIndex(serumMarket.quoteTokenIndex).mintDecimals
)
unsettledBalances[market.serumMarketExternal.toString()] = {
base: baseTokenUnsettled,
quote: quoteTokenUnsettled,
}
})
const filtered = Object.entries(unsettledBalances).filter(
([_mkt, balance]) => balance.base > 0 || balance.quote > 0
)
return Object.fromEntries(filtered)!
}, [mangoAccount, group, openOrdersAccounts])
const [settleMktAddress, setSettleMktAddress] = useState<string>('')
const { width } = useViewport()
const showTableView = width ? width > breakpoints.md : false
const handleSettleFunds = useCallback(async (mktAddress: string) => {
const client = mangoStore.getState().client
@ -53,7 +31,7 @@ const UnsettledTrades = () => {
const actions = mangoStore.getState().actions
if (!group || !mangoAccount) return
setSettleMktAddress(mktAddress)
try {
const txid = await client.serum3SettleFunds(
group,
@ -70,63 +48,139 @@ const UnsettledTrades = () => {
} catch (e: any) {
notify({
type: 'error',
title: 'Settle transaction failed',
title: t('trade:settle-funds-error'),
description: e?.message,
txid: e?.txid,
})
console.error('Settle funds error:', e)
} finally {
setSettleMktAddress('')
}
}, [])
if (!group) return null
// console.log('unsettledSpotBalances', unsettledSpotBalances)
return (
<table className="min-w-full">
<thead>
<tr>
<th className="bg-th-bkg-1 text-left">Market</th>
<th className="bg-th-bkg-1 text-right">Base</th>
<th className="bg-th-bkg-1 text-right">Quote</th>
<th className="bg-th-bkg-1 text-right"></th>
</tr>
</thead>
<tbody>
{Object.entries(unsettledSpotBalances).map(([mktAddress, balance]) => {
const market = group.getSerum3MarketByPk(new PublicKey(mktAddress))
console.log('market', mktAddress)
const base = market?.name.split('/')[0]
const quote = market?.name.split('/')[1]
return (
<tr key={mktAddress} className="text-sm">
<td>
<div className="flex items-center">
<span>{market ? market.name : ''}</span>
</div>
</td>
<td className="text-right font-mono">
{unsettledSpotBalances[mktAddress].base || 0.0} {base}
</td>
<td className="text-right font-mono">
{unsettledSpotBalances[mktAddress].quote || 0.0} {quote}
</td>
<td className="text-right">
<Button
onClick={() => handleSettleFunds(mktAddress)}
className={`text-white`}
disabled={false}
size="small"
>
<span>Settle</span>
</Button>
</td>
return connected ? (
Object.values(unsettledSpotBalances).flat().length ? (
showTableView ? (
<table className="min-w-full">
<thead>
<tr>
<th className="bg-th-bkg-1 text-left">{t('market')}</th>
<th className="bg-th-bkg-1 text-right">{t('trade:base')}</th>
<th className="bg-th-bkg-1 text-right">{t('trade:quote')}</th>
<th className="bg-th-bkg-1 text-right" />
</tr>
)
})}
</tbody>
</table>
</thead>
<tbody>
{Object.entries(unsettledSpotBalances).map(
([mktAddress, balance]) => {
const market = group.getSerum3MarketByPk(
new PublicKey(mktAddress)
)
const base = market?.name.split('/')[0]
const quote = market?.name.split('/')[1]
return (
<tr key={mktAddress} className="text-sm">
<td>
<div className="flex items-center">
<span>{market ? market.name : ''}</span>
</div>
</td>
<td className="text-right font-mono">
{unsettledSpotBalances[mktAddress].base || 0.0}{' '}
<span className="font-body tracking-wide text-th-fgd-4">
{base}
</span>
</td>
<td className="text-right font-mono">
{unsettledSpotBalances[mktAddress].quote || 0.0}{' '}
<span className="font-body tracking-wide text-th-fgd-4">
{quote}
</span>
</td>
<td>
<div className="flex justify-end">
<Tooltip content={t('trade:settle-funds')}>
<IconButton
onClick={() => handleSettleFunds(mktAddress)}
size="small"
>
{settleMktAddress === mktAddress ? (
<Loading className="h-4 w-4" />
) : (
<CheckIcon className="h-4 w-4" />
)}
</IconButton>
</Tooltip>
</div>
</td>
</tr>
)
}
)}
</tbody>
</table>
) : (
<div className="pb-20">
{Object.entries(unsettledSpotBalances).map(
([mktAddress, balance]) => {
const market = group.getSerum3MarketByPk(
new PublicKey(mktAddress)
)
const base = market?.name.split('/')[0]
const quote = market?.name.split('/')[1]
return (
<div
key={mktAddress}
className="flex items-center justify-between border-b border-th-bkg-3 p-4"
>
<div className="flex items-center">
<span>{market ? market.name : ''}</span>
</div>
<div className="flex items-center space-x-3">
{unsettledSpotBalances[mktAddress].base ? (
<span className="font-mono text-sm">
{unsettledSpotBalances[mktAddress].base}{' '}
<span className="font-body tracking-wide text-th-fgd-4">
{base}
</span>
</span>
) : null}
{unsettledSpotBalances[mktAddress].quote ? (
<span className="font-mono text-sm">
{unsettledSpotBalances[mktAddress].quote}{' '}
<span className="font-body tracking-wide text-th-fgd-4">
{quote}
</span>
</span>
) : null}
<IconButton onClick={() => handleSettleFunds(mktAddress)}>
{settleMktAddress === mktAddress ? (
<Loading className="h-4 w-4" />
) : (
<CheckIcon className="h-4 w-4" />
)}
</IconButton>
</div>
</div>
)
}
)}
</div>
)
) : (
<div className="flex flex-col items-center p-8">
<p>{t('trade:no-unsettled')}</p>
</div>
)
) : (
<div className="flex flex-col items-center p-8">
<LinkIcon className="mb-2 h-6 w-6 text-th-fgd-4" />
<p>{t('trade:connect-unsettled')}</p>
</div>
)
}

View File

@ -17,7 +17,6 @@ import EditProfileModal from '@components/modals/EditProfileModal'
const ConnectedMenu = () => {
const { t } = useTranslation('common')
// const [showProfileImageModal, setShowProfileImageModal] = useState(false)
const [showEditProfileModal, setShowEditProfileModal] = useState(false)
const set = mangoStore((s) => s.set)
const { publicKey, disconnect, wallet } = useWallet()
@ -31,6 +30,7 @@ const ConnectedMenu = () => {
set((state) => {
state.mangoAccount.current = undefined
state.connected = false
state.mangoAccount.openOrders = {}
})
disconnect()
wallet?.adapter.disconnect()

View File

@ -8,14 +8,12 @@
"account-update-success": "Account updated successfully",
"account-value": "Account Value",
"accounts": "Accounts",
"amount": "Amount",
"asset-weight": "Asset Weight",
"asset-weight-desc": "The asset weight applies a haircut to the value of the collateral in your account health calculation. The lower the asset weight, the less the asset counts towards collateral.",
"available": "Available",
"available-balance": "Available Balance",
"balance": "Balance",
"balances": "Balances",
"book": "Book",
"borrow": "Borrow",
"borrow-amount": "Borrow Amount",
"borrow-fee": "Borrow Fee",
@ -46,7 +44,6 @@
"governance": "Governance",
"health": "Health",
"health-impact": "Health Impact",
"in-orders": "In Orders",
"insufficient-sol": "Solana requires 0.00757 SOL rent to create a Mango Account. This will be returned if you close your account.",
"interest-earned": "Interest Earned",
"interest-earned-paid": "Interest Earned",
@ -54,7 +51,6 @@
"leverage": "Leverage",
"liability-weight": "Liability Weight",
"liquidity": "Liquidity",
"margin": "Margin",
"market": "Market",
"max": "Max",
"max-borrow": "Max Borrow",
@ -62,7 +58,6 @@
"new-account": "New Account",
"new-account-failed": "Failed to create account",
"new-account-success": "Your new account is ready 😎",
"oracle-price": "Oracle Price",
"pnl": "PnL",
"price": "Price",
"quantity": "Quantity",
@ -75,9 +70,6 @@
"sell": "Sell",
"settings": "Settings",
"show-zero-balances": "Show Zero Balances",
"side": "Side",
"size": "Size",
"spread": "Spread",
"stats": "Stats",
"swap": "Swap",
"time": "Time",
@ -90,11 +82,9 @@
"total-deposit-value": "Total Deposit Value",
"total-interest-value": "Total Interest Value",
"trade": "Trade",
"trades": "Trades",
"trade-history": "Trade History",
"transaction": "Transaction",
"unavailable": "Unavailable",
"unsettled": "Unsettled",
"update": "Update",
"utilization": "Utilization",
"value": "Value",

View File

@ -0,0 +1,35 @@
{
"amount": "Amount",
"base": "Base Token",
"book": "Book",
"cancel-order-error": "Failed to cancel order",
"connect-orders": "Connect to view your open orders",
"connect-unsettled": "Connect to view your unsettled trades",
"grouping": "Grouping",
"hide-asks": "Hide Asks",
"hide-bids": "Hide Bids",
"in-orders": "In Orders",
"limit-price": "Limit Price",
"margin": "Margin",
"no-orders": "No open orders...",
"no-unsettled": "No unsettled funds...",
"oracle-price": "Oracle Price",
"orders": "Orders",
"order-error": "Failed to place order",
"post": "Post",
"place-order": "Place {{side}} Order",
"placing-order": "Placing Order",
"quote": "Quote Token",
"settle-funds": "Settle Funds",
"settle-funds-error": "Failed to settle funds",
"show-asks": "Show Asks",
"show-bids": "Show Bids",
"side": "Side",
"size": "Size",
"spread": "Spread",
"tooltip-enable-margin": "Enable spot margin for this trade",
"tooltip-ioc": "Immediate or cancel orders are guaranteed to be the taker or they will be canceled.",
"tooltip-post": "Post orders are guaranteed to be the maker order or else they will be canceled.",
"trades": "Trades",
"unsettled": "Unsettled"
}

View File

@ -8,14 +8,12 @@
"account-update-success": "Account updated successfully",
"account-value": "Account Value",
"accounts": "Accounts",
"amount": "Amount",
"asset-weight": "Asset Weight",
"asset-weight-desc": "The asset weight applies a haircut to the value of the collateral in your account health calculation. The lower the asset weight, the less the asset counts towards collateral.",
"available": "Available",
"available-balance": "Available Balance",
"balance": "Balance",
"balances": "Balances",
"book": "Book",
"borrow": "Borrow",
"borrow-amount": "Borrow Amount",
"borrow-fee": "Borrow Fee",
@ -46,7 +44,6 @@
"governance": "Governance",
"health": "Health",
"health-impact": "Health Impact",
"in-orders": "In Orders",
"insufficient-sol": "Solana requires 0.00757 SOL rent to create a Mango Account. This will be returned if you close your account.",
"interest-earned": "Interest Earned",
"interest-earned-paid": "Interest Earned",
@ -54,7 +51,6 @@
"leverage": "Leverage",
"liability-weight": "Liability Weight",
"liquidity": "Liquidity",
"margin": "Margin",
"market": "Market",
"max": "Max",
"max-borrow": "Max Borrow",
@ -62,7 +58,6 @@
"new-account": "New Account",
"new-account-failed": "Failed to create account",
"new-account-success": "Your new account is ready 😎",
"oracle-price": "Oracle Price",
"pnl": "PnL",
"price": "Price",
"quantity": "Quantity",
@ -75,9 +70,6 @@
"sell": "Sell",
"settings": "Settings",
"show-zero-balances": "Show Zero Balances",
"side": "Side",
"size": "Size",
"spread": "Spread",
"stats": "Stats",
"swap": "Swap",
"time": "Time",
@ -90,11 +82,9 @@
"total-deposit-value": "Total Deposit Value",
"total-interest-value": "Total Interest Value",
"trade": "Trade",
"trades": "Trades",
"trade-history": "Trade History",
"transaction": "Transaction",
"unavailable": "Unavailable",
"unsettled": "Unsettled",
"update": "Update",
"utilization": "Utilization",
"value": "Value",

View File

@ -0,0 +1,35 @@
{
"amount": "Amount",
"base": "Base Token",
"book": "Book",
"cancel-order-error": "Failed to cancel order",
"connect-orders": "Connect to view your open orders",
"connect-unsettled": "Connect to view your unsettled trades",
"grouping": "Grouping",
"hide-asks": "Hide Asks",
"hide-bids": "Hide Bids",
"in-orders": "In Orders",
"limit-price": "Limit Price",
"margin": "Margin",
"no-orders": "No open orders...",
"no-unsettled": "No unsettled funds...",
"oracle-price": "Oracle Price",
"orders": "Orders",
"order-error": "Failed to place order",
"post": "Post",
"place-order": "Place {{side}} Order",
"placing-order": "Placing Order",
"quote": "Quote Token",
"settle-funds": "Settle Funds",
"settle-funds-error": "Failed to settle funds",
"show-asks": "Show Asks",
"show-bids": "Show Bids",
"side": "Side",
"size": "Size",
"spread": "Spread",
"tooltip-enable-margin": "Enable spot margin for this trade",
"tooltip-ioc": "Immediate or cancel orders are guaranteed to be the taker or they will be canceled.",
"tooltip-post": "Post orders are guaranteed to be the maker order or else they will be canceled.",
"trades": "Trades",
"unsettled": "Unsettled"
}

View File

@ -8,14 +8,12 @@
"account-update-success": "Account updated successfully",
"account-value": "Account Value",
"accounts": "Accounts",
"amount": "Amount",
"asset-weight": "Asset Weight",
"asset-weight-desc": "The asset weight applies a haircut to the value of the collateral in your account health calculation. The lower the asset weight, the less the asset counts towards collateral.",
"available": "Available",
"available-balance": "Available Balance",
"balance": "Balance",
"balances": "Balances",
"book": "Book",
"borrow": "Borrow",
"borrow-amount": "Borrow Amount",
"borrow-fee": "Borrow Fee",
@ -46,7 +44,6 @@
"governance": "Governance",
"health": "Health",
"health-impact": "Health Impact",
"in-orders": "In Orders",
"insufficient-sol": "Solana requires 0.00757 SOL rent to create a Mango Account. This will be returned if you close your account.",
"interest-earned": "Interest Earned",
"interest-earned-paid": "Interest Earned",
@ -54,7 +51,6 @@
"leverage": "Leverage",
"liability-weight": "Liability Weight",
"liquidity": "Liquidity",
"margin": "Margin",
"market": "Market",
"max": "Max",
"max-borrow": "Max Borrow",
@ -62,7 +58,6 @@
"new-account": "New Account",
"new-account-failed": "Failed to create account",
"new-account-success": "Your new account is ready 😎",
"oracle-price": "Oracle Price",
"pnl": "PnL",
"price": "Price",
"quantity": "Quantity",
@ -75,9 +70,6 @@
"sell": "Sell",
"settings": "Settings",
"show-zero-balances": "Show Zero Balances",
"side": "Side",
"size": "Size",
"spread": "Spread",
"stats": "Stats",
"swap": "Swap",
"time": "Time",
@ -90,11 +82,9 @@
"total-deposit-value": "Total Deposit Value",
"total-interest-value": "Total Interest Value",
"trade": "Trade",
"trades": "Trades",
"trade-history": "Trade History",
"transaction": "Transaction",
"unavailable": "Unavailable",
"unsettled": "Unsettled",
"update": "Update",
"utilization": "Utilization",
"value": "Value",

View File

@ -0,0 +1,35 @@
{
"amount": "Amount",
"base": "Base Token",
"book": "Book",
"cancel-order-error": "Failed to cancel order",
"connect-orders": "Connect to view your open orders",
"connect-unsettled": "Connect to view your unsettled trades",
"grouping": "Grouping",
"hide-asks": "Hide Asks",
"hide-bids": "Hide Bids",
"in-orders": "In Orders",
"limit-price": "Limit Price",
"margin": "Margin",
"no-orders": "No open orders...",
"no-unsettled": "No unsettled funds...",
"oracle-price": "Oracle Price",
"orders": "Orders",
"order-error": "Failed to place order",
"post": "Post",
"place-order": "Place {{side}} Order",
"placing-order": "Placing Order",
"quote": "Quote Token",
"settle-funds": "Settle Funds",
"settle-funds-error": "Failed to settle funds",
"show-asks": "Show Asks",
"show-bids": "Show Bids",
"side": "Side",
"size": "Size",
"spread": "Spread",
"tooltip-enable-margin": "Enable spot margin for this trade",
"tooltip-ioc": "Immediate or cancel orders are guaranteed to be the taker or they will be canceled.",
"tooltip-post": "Post orders are guaranteed to be the maker order or else they will be canceled.",
"trades": "Trades",
"unsettled": "Unsettled"
}

View File

@ -8,14 +8,12 @@
"account-update-success": "Account updated successfully",
"account-value": "Account Value",
"accounts": "Accounts",
"amount": "Amount",
"asset-weight": "Asset Weight",
"asset-weight-desc": "The asset weight applies a haircut to the value of the collateral in your account health calculation. The lower the asset weight, the less the asset counts towards collateral.",
"available": "Available",
"available-balance": "Available Balance",
"balance": "Balance",
"balances": "Balances",
"book": "Book",
"borrow": "Borrow",
"borrow-amount": "Borrow Amount",
"borrow-fee": "Borrow Fee",
@ -46,7 +44,6 @@
"governance": "Governance",
"health": "Health",
"health-impact": "Health Impact",
"in-orders": "In Orders",
"insufficient-sol": "Solana requires 0.00757 SOL rent to create a Mango Account. This will be returned if you close your account.",
"interest-earned": "Interest Earned",
"interest-earned-paid": "Interest Earned",
@ -54,7 +51,6 @@
"leverage": "Leverage",
"liability-weight": "Liability Weight",
"liquidity": "Liquidity",
"margin": "Margin",
"market": "Market",
"max": "Max",
"max-borrow": "Max Borrow",
@ -62,7 +58,6 @@
"new-account": "New Account",
"new-account-failed": "Failed to create account",
"new-account-success": "Your new account is ready 😎",
"oracle-price": "Oracle Price",
"pnl": "PnL",
"price": "Price",
"quantity": "Quantity",
@ -75,9 +70,6 @@
"sell": "Sell",
"settings": "Settings",
"show-zero-balances": "Show Zero Balances",
"side": "Side",
"size": "Size",
"spread": "Spread",
"stats": "Stats",
"swap": "Swap",
"time": "Time",
@ -90,11 +82,9 @@
"total-deposit-value": "Total Deposit Value",
"total-interest-value": "Total Interest Value",
"trade": "Trade",
"trades": "Trades",
"trade-history": "Trade History",
"transaction": "Transaction",
"unavailable": "Unavailable",
"unsettled": "Unsettled",
"update": "Update",
"utilization": "Utilization",
"value": "Value",

View File

@ -0,0 +1,35 @@
{
"amount": "Amount",
"base": "Base Token",
"book": "Book",
"cancel-order-error": "Failed to cancel order",
"connect-orders": "Connect to view your open orders",
"connect-unsettled": "Connect to view your unsettled trades",
"grouping": "Grouping",
"hide-asks": "Hide Asks",
"hide-bids": "Hide Bids",
"in-orders": "In Orders",
"limit-price": "Limit Price",
"margin": "Margin",
"no-orders": "No open orders...",
"no-unsettled": "No unsettled funds...",
"oracle-price": "Oracle Price",
"orders": "Orders",
"order-error": "Failed to place order",
"post": "Post",
"place-order": "Place {{side}} Order",
"placing-order": "Placing Order",
"quote": "Quote Token",
"settle-funds": "Settle Funds",
"settle-funds-error": "Failed to settle funds",
"show-asks": "Show Asks",
"show-bids": "Show Bids",
"side": "Side",
"size": "Size",
"spread": "Spread",
"tooltip-enable-margin": "Enable spot margin for this trade",
"tooltip-ioc": "Immediate or cancel orders are guaranteed to be the taker or they will be canceled.",
"tooltip-post": "Post orders are guaranteed to be the maker order or else they will be canceled.",
"trades": "Trades",
"unsettled": "Unsettled"
}