Merge branch 'tif' into main
This commit is contained in:
commit
6ff5517045
|
@ -59,6 +59,7 @@ export interface Balances extends BalancesBase {
|
||||||
value?: I80F48 | null | undefined
|
value?: I80F48 | null | undefined
|
||||||
depositRate?: I80F48 | null | undefined
|
depositRate?: I80F48 | null | undefined
|
||||||
borrowRate?: I80F48 | null | undefined
|
borrowRate?: I80F48 | null | undefined
|
||||||
|
decimals?: number | null | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OpenOrdersBalances extends BalancesBase {
|
export interface OpenOrdersBalances extends BalancesBase {
|
||||||
|
|
|
@ -1,31 +1,29 @@
|
||||||
import { useCallback } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
import { useBalances } from '../hooks/useBalances'
|
import { useBalances } from '../hooks/useBalances'
|
||||||
import useMangoStore from '../stores/useMangoStore'
|
import useMangoStore from '../stores/useMangoStore'
|
||||||
import Button, { LinkButton } from '../components/Button'
|
import Button, { LinkButton } from '../components/Button'
|
||||||
import { notify } from '../utils/notifications'
|
import { notify } from '../utils/notifications'
|
||||||
import { ArrowSmDownIcon, ExclamationIcon } from '@heroicons/react/outline'
|
import { ArrowSmDownIcon, ExclamationIcon } from '@heroicons/react/outline'
|
||||||
import { Market } from '@project-serum/serum'
|
import { Market } from '@project-serum/serum'
|
||||||
import {
|
import { getTokenBySymbol } from '@blockworks-foundation/mango-client'
|
||||||
getMarketIndexBySymbol,
|
|
||||||
getTokenBySymbol,
|
|
||||||
} from '@blockworks-foundation/mango-client'
|
|
||||||
import { useState } from 'react'
|
|
||||||
import Loading from './Loading'
|
import Loading from './Loading'
|
||||||
import { useViewport } from '../hooks/useViewport'
|
import { useViewport } from '../hooks/useViewport'
|
||||||
import { breakpoints } from './TradePageGrid'
|
import { breakpoints } from './TradePageGrid'
|
||||||
import { floorToDecimal, formatUsdValue } from '../utils'
|
import { floorToDecimal, formatUsdValue, getPrecisionDigits } from '../utils'
|
||||||
import { Table, Td, Th, TrBody, TrHead } from './TableElements'
|
import { ExpandableRow, Table, Td, Th, TrBody, TrHead } from './TableElements'
|
||||||
import { useSortableData } from '../hooks/useSortableData'
|
import { useSortableData } from '../hooks/useSortableData'
|
||||||
import DepositModal from './DepositModal'
|
import DepositModal from './DepositModal'
|
||||||
import WithdrawModal from './WithdrawModal'
|
import WithdrawModal from './WithdrawModal'
|
||||||
import { ExpandableRow } from './TableElements'
|
|
||||||
import MobileTableHeader from './mobile/MobileTableHeader'
|
import MobileTableHeader from './mobile/MobileTableHeader'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import { TransactionSignature } from '@solana/web3.js'
|
import { TransactionSignature } from '@solana/web3.js'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
const BalancesTable = ({
|
const BalancesTable = ({
|
||||||
showZeroBalances = false,
|
showZeroBalances = false,
|
||||||
showDepositWithdraw = false,
|
showDepositWithdraw = false,
|
||||||
|
clickToPopulateTradeForm = false,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
const [showDepositModal, setShowDepositModal] = useState(false)
|
const [showDepositModal, setShowDepositModal] = useState(false)
|
||||||
|
@ -59,34 +57,42 @@ const BalancesTable = ({
|
||||||
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
|
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
|
||||||
const wallet = useMangoStore((s) => s.wallet.current)
|
const wallet = useMangoStore((s) => s.wallet.current)
|
||||||
const canWithdraw = mangoAccount?.owner.equals(wallet.publicKey)
|
const canWithdraw = mangoAccount?.owner.equals(wallet.publicKey)
|
||||||
|
const { asPath } = useRouter()
|
||||||
|
|
||||||
const handleSizeClick = (size, symbol) => {
|
const handleSizeClick = (size, symbol) => {
|
||||||
const step = selectedMarket.minOrderSize
|
const minOrderSize = selectedMarket.minOrderSize
|
||||||
const marketIndex = getMarketIndexBySymbol(
|
const sizePrecisionDigits = getPrecisionDigits(minOrderSize)
|
||||||
mangoGroupConfig,
|
const marketIndex = marketConfig.marketIndex
|
||||||
marketConfig.baseSymbol
|
|
||||||
)
|
|
||||||
const priceOrDefault = price
|
const priceOrDefault = price
|
||||||
? price
|
? price
|
||||||
: mangoGroup.getPrice(marketIndex, mangoGroupCache).toNumber()
|
: mangoGroup.getPriceUi(marketIndex, mangoGroupCache)
|
||||||
if (symbol === 'USDC') {
|
|
||||||
const baseSize = Math.floor(size / priceOrDefault / step) * step
|
|
||||||
setMangoStore((state) => {
|
|
||||||
state.tradeForm.baseSize = baseSize
|
|
||||||
state.tradeForm.quoteSize = baseSize * priceOrDefault
|
|
||||||
state.tradeForm.side = 'buy'
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
const roundedSize = Math.round(size / step) * step
|
|
||||||
const quoteSize = roundedSize * priceOrDefault
|
|
||||||
setMangoStore((state) => {
|
|
||||||
state.tradeForm.baseSize = roundedSize
|
|
||||||
state.tradeForm.quoteSize = quoteSize
|
|
||||||
state.tradeForm.side = 'sell'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let roundedSize, side
|
||||||
|
if (symbol === 'USDC') {
|
||||||
|
roundedSize = parseFloat(
|
||||||
|
(
|
||||||
|
Math.abs(size) / priceOrDefault +
|
||||||
|
(size < 0 ? minOrderSize / 2 : -minOrderSize / 2)
|
||||||
|
) // round up so neg USDC gets cleared
|
||||||
|
.toFixed(sizePrecisionDigits)
|
||||||
|
)
|
||||||
|
side = size > 0 ? 'buy' : 'sell'
|
||||||
|
} else {
|
||||||
|
roundedSize = parseFloat(
|
||||||
|
(
|
||||||
|
Math.abs(size) + (size < 0 ? minOrderSize / 2 : -minOrderSize / 2)
|
||||||
|
).toFixed(sizePrecisionDigits)
|
||||||
|
)
|
||||||
|
side = size > 0 ? 'sell' : 'buy'
|
||||||
|
}
|
||||||
|
const quoteSize = parseFloat((roundedSize * priceOrDefault).toFixed(2))
|
||||||
|
setMangoStore((state) => {
|
||||||
|
state.tradeForm.baseSize = roundedSize
|
||||||
|
state.tradeForm.quoteSize = quoteSize
|
||||||
|
state.tradeForm.side = side
|
||||||
|
})
|
||||||
|
}
|
||||||
const handleOpenDepositModal = useCallback((symbol) => {
|
const handleOpenDepositModal = useCallback((symbol) => {
|
||||||
setActionSymbol(symbol)
|
setActionSymbol(symbol)
|
||||||
setShowDepositModal(true)
|
setShowDepositModal(true)
|
||||||
|
@ -158,6 +164,7 @@ const BalancesTable = ({
|
||||||
</div>
|
</div>
|
||||||
{unsettledBalances.map((bal) => {
|
{unsettledBalances.map((bal) => {
|
||||||
const tokenConfig = getTokenBySymbol(mangoGroupConfig, bal.symbol)
|
const tokenConfig = getTokenBySymbol(mangoGroupConfig, bal.symbol)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="border-b border-th-bkg-4 flex items-center justify-between py-4 last:border-b-0 last:pb-0"
|
className="border-b border-th-bkg-4 flex items-center justify-between py-4 last:border-b-0 last:pb-0"
|
||||||
|
@ -356,20 +363,46 @@ const BalancesTable = ({
|
||||||
className={`mr-2.5`}
|
className={`mr-2.5`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{balance.symbol}
|
{balance.symbol === 'USDC' ||
|
||||||
|
decodeURIComponent(asPath).includes(
|
||||||
|
`${balance.symbol}/USDC`
|
||||||
|
) ? (
|
||||||
|
<span>{balance.symbol}</span>
|
||||||
|
) : (
|
||||||
|
<Link
|
||||||
|
href={{
|
||||||
|
pathname: '/',
|
||||||
|
query: { name: `${balance.symbol}/USDC` },
|
||||||
|
}}
|
||||||
|
shallow={true}
|
||||||
|
>
|
||||||
|
<a className="text-th-fgd-1 underline hover:no-underline hover:text-th-fgd-1">
|
||||||
|
{balance.symbol}
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Td>
|
</Td>
|
||||||
<Td>{balance.deposits.toFixed()}</Td>
|
<Td>
|
||||||
<Td>{balance.borrows.toFixed()}</Td>
|
{balance.deposits.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: balance.decimals,
|
||||||
|
})}
|
||||||
|
</Td>
|
||||||
|
<Td>
|
||||||
|
{balance.borrows.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: balance.decimals,
|
||||||
|
})}
|
||||||
|
</Td>
|
||||||
<Td>{balance.orders}</Td>
|
<Td>{balance.orders}</Td>
|
||||||
<Td>{balance.unsettled}</Td>
|
<Td>{balance.unsettled}</Td>
|
||||||
<Td>
|
<Td>
|
||||||
{marketConfig.kind === 'spot' &&
|
{marketConfig.kind === 'spot' &&
|
||||||
marketConfig.name.includes(balance.symbol) &&
|
marketConfig.name.includes(balance.symbol) &&
|
||||||
selectedMarket ? (
|
selectedMarket &&
|
||||||
|
clickToPopulateTradeForm ? (
|
||||||
<span
|
<span
|
||||||
className={
|
className={
|
||||||
balance.net.toNumber() > 0
|
balance.net.toNumber() != 0
|
||||||
? 'cursor-pointer underline hover:no-underline'
|
? 'cursor-pointer underline hover:no-underline'
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
@ -377,10 +410,14 @@ const BalancesTable = ({
|
||||||
handleSizeClick(balance.net, balance.symbol)
|
handleSizeClick(balance.net, balance.symbol)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{balance.net.toFixed()}
|
{balance.net.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: balance.decimals,
|
||||||
|
})}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
balance.net.toFixed()
|
balance.net.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: balance.decimals,
|
||||||
|
})
|
||||||
)}
|
)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td>{formatUsdValue(balance.value.toNumber())}</Td>
|
<Td>{formatUsdValue(balance.value.toNumber())}</Td>
|
||||||
|
@ -464,7 +501,9 @@ const BalancesTable = ({
|
||||||
{balance.symbol}
|
{balance.symbol}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-th-fgd-1 text-right">
|
<div className="text-th-fgd-1 text-right">
|
||||||
{balance.net.toFixed()}
|
{balance.net.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: balance.decimals,
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -477,25 +516,33 @@ const BalancesTable = ({
|
||||||
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
||||||
{t('deposits')}
|
{t('deposits')}
|
||||||
</div>
|
</div>
|
||||||
{balance.deposits.toFixed()}
|
{balance.deposits.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: balance.decimals,
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-left">
|
<div className="text-left">
|
||||||
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
||||||
{t('borrows')}
|
{t('borrows')}
|
||||||
</div>
|
</div>
|
||||||
{balance.borrows.toFixed()}
|
{balance.borrows.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: balance.decimals,
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-left">
|
<div className="text-left">
|
||||||
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
||||||
{t('in-orders')}
|
{t('in-orders')}
|
||||||
</div>
|
</div>
|
||||||
{balance.orders.toFixed()}
|
{balance.orders.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: balance.decimals,
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-left">
|
<div className="text-left">
|
||||||
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
||||||
{t('unsettled')}
|
{t('unsettled')}
|
||||||
</div>
|
</div>
|
||||||
{balance.unsettled.toFixed()}
|
{balance.unsettled.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: balance.decimals,
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-left">
|
<div className="text-left">
|
||||||
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
||||||
|
@ -544,7 +591,9 @@ const BalancesTable = ({
|
||||||
tokenSymbol={actionSymbol}
|
tokenSymbol={actionSymbol}
|
||||||
repayAmount={
|
repayAmount={
|
||||||
balance.borrows.toNumber() > 0
|
balance.borrows.toNumber() > 0
|
||||||
? balance.borrows.toFixed()
|
? balance.borrows.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: balance.decimals,
|
||||||
|
})
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
import { ElementTitle } from './styles'
|
import { ElementTitle } from './styles'
|
||||||
import useMangoStore from '../stores/useMangoStore'
|
import useMangoStore from '../stores/useMangoStore'
|
||||||
import { i80f48ToPercent, floorToDecimal } from '../utils/index'
|
import { getPrecisionDigits, i80f48ToPercent } from '../utils'
|
||||||
import Tooltip from './Tooltip'
|
import Tooltip from './Tooltip'
|
||||||
import {
|
import { nativeI80F48ToUi } from '@blockworks-foundation/mango-client'
|
||||||
getMarketIndexBySymbol,
|
|
||||||
nativeI80F48ToUi,
|
|
||||||
} from '@blockworks-foundation/mango-client'
|
|
||||||
import { useViewport } from '../hooks/useViewport'
|
import { useViewport } from '../hooks/useViewport'
|
||||||
import { breakpoints } from './TradePageGrid'
|
import { breakpoints } from './TradePageGrid'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
@ -27,30 +24,38 @@ export default function MarketBalances() {
|
||||||
const isMobile = width ? width < breakpoints.sm : false
|
const isMobile = width ? width < breakpoints.sm : false
|
||||||
|
|
||||||
const handleSizeClick = (size, symbol) => {
|
const handleSizeClick = (size, symbol) => {
|
||||||
const step = selectedMarket.minOrderSize
|
const minOrderSize = selectedMarket.minOrderSize
|
||||||
const marketIndex = getMarketIndexBySymbol(
|
const sizePrecisionDigits = getPrecisionDigits(minOrderSize)
|
||||||
mangoGroupConfig,
|
const marketIndex = marketConfig.marketIndex
|
||||||
marketConfig.baseSymbol
|
|
||||||
)
|
|
||||||
const priceOrDefault = price
|
const priceOrDefault = price
|
||||||
? price
|
? price
|
||||||
: mangoGroup.getPrice(marketIndex, mangoGroupCache).toNumber()
|
: mangoGroup.getPriceUi(marketIndex, mangoGroupCache)
|
||||||
|
|
||||||
|
let roundedSize, side
|
||||||
if (symbol === 'USDC') {
|
if (symbol === 'USDC') {
|
||||||
const baseSize = Math.floor(size / priceOrDefault / step) * step
|
roundedSize = parseFloat(
|
||||||
setMangoStore((state) => {
|
(
|
||||||
state.tradeForm.baseSize = baseSize
|
Math.abs(size) / priceOrDefault +
|
||||||
state.tradeForm.quoteSize = baseSize * priceOrDefault
|
(size < 0 ? minOrderSize / 2 : -minOrderSize / 2)
|
||||||
state.tradeForm.side = 'buy'
|
) // round up so neg USDC gets cleared
|
||||||
})
|
.toFixed(sizePrecisionDigits)
|
||||||
|
)
|
||||||
|
side = size > 0 ? 'buy' : 'sell'
|
||||||
} else {
|
} else {
|
||||||
const roundedSize = Math.round(size / step) * step
|
roundedSize = parseFloat(
|
||||||
const quoteSize = roundedSize * priceOrDefault
|
(
|
||||||
setMangoStore((state) => {
|
Math.abs(size) + (size < 0 ? minOrderSize / 2 : -minOrderSize / 2)
|
||||||
state.tradeForm.baseSize = roundedSize
|
).toFixed(sizePrecisionDigits)
|
||||||
state.tradeForm.quoteSize = quoteSize
|
)
|
||||||
state.tradeForm.side = 'sell'
|
side = size > 0 ? 'sell' : 'buy'
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
const quoteSize = parseFloat((roundedSize * priceOrDefault).toFixed(2))
|
||||||
|
setMangoStore((state) => {
|
||||||
|
state.tradeForm.baseSize = roundedSize
|
||||||
|
state.tradeForm.quoteSize = quoteSize
|
||||||
|
state.tradeForm.side = side
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mangoGroup || !selectedMarket) return null
|
if (!mangoGroup || !selectedMarket) return null
|
||||||
|
@ -67,31 +72,22 @@ export default function MarketBalances() {
|
||||||
.reverse()
|
.reverse()
|
||||||
.map(({ decimals, symbol, mintKey }) => {
|
.map(({ decimals, symbol, mintKey }) => {
|
||||||
const tokenIndex = mangoGroup.getTokenIndex(mintKey)
|
const tokenIndex = mangoGroup.getTokenIndex(mintKey)
|
||||||
const deposit = mangoAccount
|
const balance = mangoAccount
|
||||||
? mangoAccount.getUiDeposit(
|
? nativeI80F48ToUi(
|
||||||
mangoGroupCache.rootBankCache[tokenIndex],
|
mangoAccount.getNet(
|
||||||
mangoGroup,
|
mangoGroupCache.rootBankCache[tokenIndex],
|
||||||
tokenIndex
|
tokenIndex
|
||||||
|
),
|
||||||
|
decimals
|
||||||
)
|
)
|
||||||
: null
|
: 0
|
||||||
const borrow = mangoAccount
|
|
||||||
? mangoAccount.getUiBorrow(
|
|
||||||
mangoGroupCache.rootBankCache[tokenIndex],
|
|
||||||
mangoGroup,
|
|
||||||
tokenIndex
|
|
||||||
)
|
|
||||||
: null
|
|
||||||
|
|
||||||
const availableBalance = mangoAccount
|
const availableBalance = mangoAccount
|
||||||
? floorToDecimal(
|
? nativeI80F48ToUi(
|
||||||
nativeI80F48ToUi(
|
mangoAccount.getAvailableBalance(
|
||||||
mangoAccount.getAvailableBalance(
|
mangoGroup,
|
||||||
mangoGroup,
|
mangoGroupCache,
|
||||||
mangoGroupCache,
|
tokenIndex
|
||||||
tokenIndex
|
),
|
||||||
),
|
|
||||||
decimals
|
|
||||||
).toNumber(),
|
|
||||||
decimals
|
decimals
|
||||||
)
|
)
|
||||||
: 0
|
: 0
|
||||||
|
@ -115,19 +111,20 @@ export default function MarketBalances() {
|
||||||
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
<div className="pb-0.5 text-th-fgd-3 text-xs">
|
||||||
{t('balance')}
|
{t('balance')}
|
||||||
</div>
|
</div>
|
||||||
<div className={`text-th-fgd-1`}>
|
<div
|
||||||
|
className={`text-th-fgd-1 ${
|
||||||
|
balance != 0
|
||||||
|
? 'cursor-pointer underline hover:no-underline'
|
||||||
|
: ''
|
||||||
|
}`}
|
||||||
|
onClick={() => handleSizeClick(balance, symbol)}
|
||||||
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<DataLoader />
|
<DataLoader />
|
||||||
) : mangoAccount ? (
|
|
||||||
deposit.gt(borrow) ? (
|
|
||||||
deposit.toFixed()
|
|
||||||
) : borrow.toNumber() > 0 ? (
|
|
||||||
`-${borrow.toFixed()}`
|
|
||||||
) : (
|
|
||||||
0
|
|
||||||
)
|
|
||||||
) : (
|
) : (
|
||||||
0
|
balance.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: decimals,
|
||||||
|
})
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -147,10 +144,10 @@ export default function MarketBalances() {
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<DataLoader />
|
<DataLoader />
|
||||||
) : mangoAccount ? (
|
|
||||||
availableBalance
|
|
||||||
) : (
|
) : (
|
||||||
0
|
availableBalance.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: decimals,
|
||||||
|
})
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -59,20 +59,20 @@ const MarketCloseModal: FunctionComponent<MarketCloseModalProps> = ({
|
||||||
// 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
|
||||||
|
|
||||||
const txid = await mangoClient.placePerpOrder(
|
const txid = await mangoClient.placePerpOrder2(
|
||||||
mangoGroup,
|
mangoGroup,
|
||||||
mangoAccount,
|
mangoAccount,
|
||||||
mangoGroup.mangoCache,
|
|
||||||
market,
|
market,
|
||||||
wallet,
|
wallet,
|
||||||
side,
|
side,
|
||||||
referencePrice * (1 + (side === 'buy' ? 1 : -1) * maxSlippage),
|
referencePrice * (1 + (side === 'buy' ? 1 : -1) * maxSlippage),
|
||||||
size,
|
size,
|
||||||
'ioc',
|
{
|
||||||
0, // client order id
|
orderType: 'ioc',
|
||||||
side === 'buy' ? askInfo : bidInfo,
|
bookSideInfo: side === 'buy' ? askInfo : bidInfo,
|
||||||
true, // reduce only
|
reduceOnly: true,
|
||||||
referrerPk ? referrerPk : undefined
|
referrerMangoAccountPk: referrerPk ? referrerPk : undefined,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
await sleep(500)
|
await sleep(500)
|
||||||
actions.reloadMangoAccount()
|
actions.reloadMangoAccount()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useCallback, useMemo, useState } from 'react'
|
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import useMangoStore from '../stores/useMangoStore'
|
import useMangoStore, { SECONDS } from '../stores/useMangoStore'
|
||||||
import usePrevious from '../hooks/usePrevious'
|
import usePrevious from '../hooks/usePrevious'
|
||||||
import useInterval from '../hooks/useInterval'
|
import useInterval from '../hooks/useInterval'
|
||||||
import ChartApi from '../utils/chartDataConnector'
|
import ChartApi from '../utils/chartDataConnector'
|
||||||
|
@ -7,10 +7,10 @@ import UiLock from './UiLock'
|
||||||
import ManualRefresh from './ManualRefresh'
|
import ManualRefresh from './ManualRefresh'
|
||||||
import useOraclePrice from '../hooks/useOraclePrice'
|
import useOraclePrice from '../hooks/useOraclePrice'
|
||||||
import DayHighLow from './DayHighLow'
|
import DayHighLow from './DayHighLow'
|
||||||
import { useEffect } from 'react'
|
|
||||||
import {
|
import {
|
||||||
getDecimalCount,
|
getPrecisionDigits,
|
||||||
patchInternalMarketName,
|
patchInternalMarketName,
|
||||||
|
perpContractPrecision,
|
||||||
usdFormatter,
|
usdFormatter,
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
import { PerpMarket } from '@blockworks-foundation/mango-client'
|
import { PerpMarket } from '@blockworks-foundation/mango-client'
|
||||||
|
@ -20,7 +20,6 @@ import { breakpoints } from './TradePageGrid'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import SwitchMarketDropdown from './SwitchMarketDropdown'
|
import SwitchMarketDropdown from './SwitchMarketDropdown'
|
||||||
import Tooltip from './Tooltip'
|
import Tooltip from './Tooltip'
|
||||||
import { SECONDS } from '../stores/useMangoStore'
|
|
||||||
|
|
||||||
export function calculateFundingRate(perpStats, perpMarket) {
|
export function calculateFundingRate(perpStats, perpMarket) {
|
||||||
const oldestStat = perpStats[perpStats.length - 1]
|
const oldestStat = perpStats[perpStats.length - 1]
|
||||||
|
@ -190,7 +189,11 @@ const MarketDetails = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="text-th-fgd-1 md:text-xs">
|
<div className="text-th-fgd-1 md:text-xs">
|
||||||
{oraclePrice && selectedMarket
|
{oraclePrice && selectedMarket
|
||||||
? oraclePrice.toFixed(getDecimalCount(selectedMarket.tickSize))
|
? oraclePrice.toNumber().toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: getPrecisionDigits(
|
||||||
|
selectedMarket.tickSize
|
||||||
|
),
|
||||||
|
})
|
||||||
: '--'}
|
: '--'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -255,7 +258,9 @@ const MarketDetails = () => {
|
||||||
{selectedMarket ? (
|
{selectedMarket ? (
|
||||||
`${parseOpenInterest(
|
`${parseOpenInterest(
|
||||||
selectedMarket as PerpMarket
|
selectedMarket as PerpMarket
|
||||||
)} ${baseSymbol}`
|
).toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: perpContractPrecision[baseSymbol],
|
||||||
|
})} ${baseSymbol}`
|
||||||
) : (
|
) : (
|
||||||
<MarketDataLoader />
|
<MarketDataLoader />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
import { useCallback, useMemo, useState } from 'react'
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
import { ElementTitle } from './styles'
|
import { ElementTitle } from './styles'
|
||||||
import useMangoStore from '../stores/useMangoStore'
|
import useMangoStore from '../stores/useMangoStore'
|
||||||
import { formatUsdValue } from '../utils/index'
|
import {
|
||||||
|
formatUsdValue,
|
||||||
|
getPrecisionDigits,
|
||||||
|
perpContractPrecision,
|
||||||
|
} from '../utils'
|
||||||
import Button, { LinkButton } from './Button'
|
import Button, { LinkButton } from './Button'
|
||||||
import Tooltip from './Tooltip'
|
import Tooltip from './Tooltip'
|
||||||
import PerpSideBadge from './PerpSideBadge'
|
import PerpSideBadge from './PerpSideBadge'
|
||||||
|
@ -92,18 +96,17 @@ export default function MarketPosition() {
|
||||||
perpAccount = mangoAccount.perpAccounts[marketIndex]
|
perpAccount = mangoAccount.perpAccounts[marketIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSizeClick = (size, side) => {
|
const handleSizeClick = (size) => {
|
||||||
const step = selectedMarket.minOrderSize
|
const sizePrecisionDigits = getPrecisionDigits(selectedMarket.minOrderSize)
|
||||||
|
|
||||||
const priceOrDefault = price
|
const priceOrDefault = price
|
||||||
? price
|
? price
|
||||||
: mangoGroup.getPrice(marketIndex, mangoCache).toNumber()
|
: mangoGroup.getPriceUi(marketIndex, mangoCache)
|
||||||
const roundedSize = Math.round(size / step) * step
|
const roundedSize = parseFloat(Math.abs(size).toFixed(sizePrecisionDigits))
|
||||||
const quoteSize = roundedSize * priceOrDefault
|
const quoteSize = parseFloat((roundedSize * priceOrDefault).toFixed(2))
|
||||||
setMangoStore((state) => {
|
setMangoStore((state) => {
|
||||||
state.tradeForm.baseSize = roundedSize
|
state.tradeForm.baseSize = roundedSize
|
||||||
state.tradeForm.quoteSize = quoteSize
|
state.tradeForm.quoteSize = quoteSize
|
||||||
state.tradeForm.side = side === 'buy' ? 'sell' : 'buy'
|
state.tradeForm.side = size > 0 ? 'sell' : 'buy'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,14 +180,11 @@ export default function MarketPosition() {
|
||||||
) : basePosition ? (
|
) : basePosition ? (
|
||||||
<span
|
<span
|
||||||
className="cursor-pointer underline hover:no-underline"
|
className="cursor-pointer underline hover:no-underline"
|
||||||
onClick={() =>
|
onClick={() => handleSizeClick(basePosition)}
|
||||||
handleSizeClick(
|
|
||||||
Math.abs(basePosition),
|
|
||||||
basePosition > 0 ? 'buy' : 'sell'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{`${Math.abs(basePosition)} ${baseSymbol}`}
|
{`${Math.abs(basePosition).toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: perpContractPrecision[baseSymbol],
|
||||||
|
})} ${baseSymbol}`}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
`0 ${baseSymbol}`
|
`0 ${baseSymbol}`
|
||||||
|
|
|
@ -99,7 +99,11 @@ const DesktopTable = ({
|
||||||
</Td>
|
</Td>
|
||||||
{editOrderIndex !== index ? (
|
{editOrderIndex !== index ? (
|
||||||
<>
|
<>
|
||||||
<Td className="w-[14.286%]">{order.size}</Td>
|
<Td className="w-[14.286%]">
|
||||||
|
{order.size.toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits: 4,
|
||||||
|
})}
|
||||||
|
</Td>
|
||||||
<Td className="w-[14.286%]">
|
<Td className="w-[14.286%]">
|
||||||
{usdFormatter(order.price, decimals)}
|
{usdFormatter(order.price, decimals)}
|
||||||
</Td>
|
</Td>
|
||||||
|
|
|
@ -9,7 +9,11 @@ import Button 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'
|
||||||
import { formatUsdValue } from '../utils'
|
import {
|
||||||
|
formatUsdValue,
|
||||||
|
getPrecisionDigits,
|
||||||
|
perpContractPrecision,
|
||||||
|
} from '../utils'
|
||||||
import Loading from './Loading'
|
import Loading from './Loading'
|
||||||
import MarketCloseModal from './MarketCloseModal'
|
import MarketCloseModal from './MarketCloseModal'
|
||||||
import PerpSideBadge from './PerpSideBadge'
|
import PerpSideBadge from './PerpSideBadge'
|
||||||
|
@ -40,15 +44,15 @@ const PositionsTable = () => {
|
||||||
setShowMarketCloseModal(false)
|
setShowMarketCloseModal(false)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleSizeClick = (size, side, indexPrice) => {
|
const handleSizeClick = (size, indexPrice) => {
|
||||||
const step = selectedMarket.minOrderSize
|
const sizePrecisionDigits = getPrecisionDigits(selectedMarket.minOrderSize)
|
||||||
const priceOrDefault = price ? price : indexPrice
|
const priceOrDefault = price ? price : indexPrice
|
||||||
const roundedSize = Math.round(size / step) * step
|
const roundedSize = parseFloat(Math.abs(size).toFixed(sizePrecisionDigits))
|
||||||
const quoteSize = roundedSize * priceOrDefault
|
const quoteSize = parseFloat((roundedSize * priceOrDefault).toFixed(2))
|
||||||
setMangoStore((state) => {
|
setMangoStore((state) => {
|
||||||
state.tradeForm.baseSize = roundedSize
|
state.tradeForm.baseSize = roundedSize
|
||||||
state.tradeForm.quoteSize = quoteSize
|
state.tradeForm.quoteSize = quoteSize
|
||||||
state.tradeForm.side = side === 'buy' ? 'sell' : 'buy'
|
state.tradeForm.side = size > 0 ? 'sell' : 'buy'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +133,12 @@ const PositionsTable = () => {
|
||||||
breakEvenPrice,
|
breakEvenPrice,
|
||||||
unrealizedPnl,
|
unrealizedPnl,
|
||||||
}) => {
|
}) => {
|
||||||
|
const basePositionUi = Math.abs(
|
||||||
|
basePosition
|
||||||
|
).toLocaleString(undefined, {
|
||||||
|
maximumFractionDigits:
|
||||||
|
perpContractPrecision[marketConfig.baseSymbol],
|
||||||
|
})
|
||||||
return (
|
return (
|
||||||
<TrBody key={`${marketConfig.marketIndex}`}>
|
<TrBody key={`${marketConfig.marketIndex}`}>
|
||||||
<Td>
|
<Td>
|
||||||
|
@ -169,22 +179,14 @@ const PositionsTable = () => {
|
||||||
<span
|
<span
|
||||||
className="cursor-pointer underline hover:no-underline"
|
className="cursor-pointer underline hover:no-underline"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handleSizeClick(
|
handleSizeClick(basePosition, indexPrice)
|
||||||
Math.abs(basePosition),
|
|
||||||
basePosition > 0 ? 'buy' : 'sell',
|
|
||||||
indexPrice
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{`${Math.abs(basePosition)} ${
|
{`${basePositionUi} ${marketConfig.baseSymbol}`}
|
||||||
marketConfig.baseSymbol
|
|
||||||
}`}
|
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span>
|
<span>
|
||||||
{`${Math.abs(basePosition)} ${
|
{`${basePositionUi} ${marketConfig.baseSymbol}`}
|
||||||
marketConfig.baseSymbol
|
|
||||||
}`}
|
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</Td>
|
</Td>
|
||||||
|
|
|
@ -55,7 +55,7 @@ const TabContent = ({ activeTab }) => {
|
||||||
case 'Orders':
|
case 'Orders':
|
||||||
return <OpenOrdersTable />
|
return <OpenOrdersTable />
|
||||||
case 'Balances':
|
case 'Balances':
|
||||||
return <BalancesTable />
|
return <BalancesTable clickToPopulateTradeForm />
|
||||||
case 'Trade History':
|
case 'Trade History':
|
||||||
return <TradeHistoryTable numTrades={100} />
|
return <TradeHistoryTable numTrades={100} />
|
||||||
case 'Positions':
|
case 'Positions':
|
||||||
|
@ -63,7 +63,7 @@ const TabContent = ({ activeTab }) => {
|
||||||
case 'Fee Discount':
|
case 'Fee Discount':
|
||||||
return <FeeDiscountsTable />
|
return <FeeDiscountsTable />
|
||||||
default:
|
default:
|
||||||
return <BalancesTable />
|
return <BalancesTable clickToPopulateTradeForm />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,11 @@ import {
|
||||||
InformationCircleIcon,
|
InformationCircleIcon,
|
||||||
} from '@heroicons/react/outline'
|
} from '@heroicons/react/outline'
|
||||||
import { notify } from '../../utils/notifications'
|
import { notify } from '../../utils/notifications'
|
||||||
import { calculateTradePrice, getDecimalCount } from '../../utils'
|
import {
|
||||||
|
calculateTradePrice,
|
||||||
|
getDecimalCount,
|
||||||
|
percentFormat,
|
||||||
|
} from '../../utils'
|
||||||
import { floorToDecimal } from '../../utils/index'
|
import { floorToDecimal } from '../../utils/index'
|
||||||
import useMangoStore, { Orderbook } from '../../stores/useMangoStore'
|
import useMangoStore, { Orderbook } from '../../stores/useMangoStore'
|
||||||
import Button, { LinkButton } from '../Button'
|
import Button, { LinkButton } from '../Button'
|
||||||
|
@ -658,20 +662,21 @@ export default function AdvancedTradeForm({
|
||||||
)
|
)
|
||||||
actions.reloadOrders()
|
actions.reloadOrders()
|
||||||
} else {
|
} else {
|
||||||
txid = await mangoClient.placePerpOrder(
|
txid = await mangoClient.placePerpOrder2(
|
||||||
mangoGroup,
|
mangoGroup,
|
||||||
mangoAccount,
|
mangoAccount,
|
||||||
mangoGroup.mangoCache,
|
|
||||||
market,
|
market,
|
||||||
wallet,
|
wallet,
|
||||||
side,
|
side,
|
||||||
perpOrderPrice,
|
perpOrderPrice,
|
||||||
baseSize,
|
baseSize,
|
||||||
perpOrderType,
|
{
|
||||||
Date.now(),
|
orderType: perpOrderType,
|
||||||
side === 'buy' ? askInfo : bidInfo, // book side used for ConsumeEvents
|
clientOrderId: Date.now(),
|
||||||
reduceOnly,
|
bookSideInfo: side === 'buy' ? askInfo : bidInfo, // book side used for ConsumeEvents
|
||||||
referrerPk ? referrerPk : undefined
|
reduceOnly,
|
||||||
|
referrerMangoAccountPk: referrerPk ? referrerPk : undefined,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1108,12 +1113,12 @@ export default function AdvancedTradeForm({
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col md:flex-row text-xs text-th-fgd-4 px-6 mt-2.5 items-center justify-center">
|
<div className="flex flex-col md:flex-row text-xs text-th-fgd-4 px-6 mt-2.5 items-center justify-center">
|
||||||
<div>
|
<div>
|
||||||
{t('maker-fee')}: {(makerFee * 100).toFixed(2)}%{' '}
|
{t('maker-fee')}: {percentFormat.format(makerFee)}{' '}
|
||||||
</div>
|
</div>
|
||||||
<span className="hidden md:block md:px-1">|</span>
|
<span className="hidden md:block md:px-1">|</span>
|
||||||
<div>
|
<div>
|
||||||
{' '}
|
{' '}
|
||||||
{t('taker-fee')}: {(takerFee * 100).toFixed(3)}%
|
{t('taker-fee')}: {percentFormat.format(takerFee)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -316,18 +316,18 @@ export default function SimpleTradeForm({ initLeverage }) {
|
||||||
orderType
|
orderType
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
txid = await mangoClient.placePerpOrder(
|
txid = await mangoClient.placePerpOrder2(
|
||||||
mangoGroup,
|
mangoGroup,
|
||||||
mangoAccount,
|
mangoAccount,
|
||||||
mangoGroup.mangoCache,
|
|
||||||
market,
|
market,
|
||||||
wallet,
|
wallet,
|
||||||
side,
|
side,
|
||||||
orderPrice,
|
orderPrice,
|
||||||
baseSize,
|
baseSize,
|
||||||
orderType,
|
{
|
||||||
0,
|
orderType,
|
||||||
side === 'buy' ? askInfo : bidInfo
|
bookSideInfo: side === 'buy' ? askInfo : bidInfo,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
notify({ title: t('successfully-placed'), txid })
|
notify({ title: t('successfully-placed'), txid })
|
||||||
|
|
|
@ -107,6 +107,7 @@ export function useBalances(): Balances[] {
|
||||||
value: value(nativeBaseLocked, tokenIndex),
|
value: value(nativeBaseLocked, tokenIndex),
|
||||||
depositRate: i80f48ToPercent(mangoGroup.getDepositRate(tokenIndex)),
|
depositRate: i80f48ToPercent(mangoGroup.getDepositRate(tokenIndex)),
|
||||||
borrowRate: i80f48ToPercent(mangoGroup.getBorrowRate(tokenIndex)),
|
borrowRate: i80f48ToPercent(mangoGroup.getBorrowRate(tokenIndex)),
|
||||||
|
decimals: mangoGroup.tokens[tokenIndex].decimals,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
market: null,
|
market: null,
|
||||||
|
@ -134,6 +135,7 @@ export function useBalances(): Balances[] {
|
||||||
value: value(nativeQuoteLocked, quoteCurrencyIndex),
|
value: value(nativeQuoteLocked, quoteCurrencyIndex),
|
||||||
depositRate: i80f48ToPercent(mangoGroup.getDepositRate(tokenIndex)),
|
depositRate: i80f48ToPercent(mangoGroup.getDepositRate(tokenIndex)),
|
||||||
borrowRate: i80f48ToPercent(mangoGroup.getBorrowRate(tokenIndex)),
|
borrowRate: i80f48ToPercent(mangoGroup.getBorrowRate(tokenIndex)),
|
||||||
|
decimals: mangoGroup.tokens[quoteCurrencyIndex].decimals,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
balances.push(marketPair)
|
balances.push(marketPair)
|
||||||
|
@ -172,6 +174,7 @@ export function useBalances(): Balances[] {
|
||||||
value,
|
value,
|
||||||
depositRate,
|
depositRate,
|
||||||
borrowRate,
|
borrowRate,
|
||||||
|
decimals: mangoGroup.tokens[QUOTE_INDEX].decimals,
|
||||||
},
|
},
|
||||||
].concat(baseBalances)
|
].concat(baseBalances)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { AccountInfo, PublicKey } from '@solana/web3.js'
|
import { AccountInfo, PublicKey } from '@solana/web3.js'
|
||||||
import useMangoStore, { programId } from '../stores/useMangoStore'
|
import useMangoStore, { programId, SECONDS } from '../stores/useMangoStore'
|
||||||
import useInterval from './useInterval'
|
import useInterval from './useInterval'
|
||||||
import { Orderbook as SpotOrderBook, Market } from '@project-serum/serum'
|
import { Market, Orderbook as SpotOrderBook } from '@project-serum/serum'
|
||||||
import {
|
import {
|
||||||
BookSide,
|
BookSide,
|
||||||
BookSideLayout,
|
BookSideLayout,
|
||||||
|
@ -19,7 +19,6 @@ import {
|
||||||
marketSelector,
|
marketSelector,
|
||||||
marketsSelector,
|
marketsSelector,
|
||||||
} from '../stores/selectors'
|
} from '../stores/selectors'
|
||||||
import { SECONDS } from '../stores/useMangoStore'
|
|
||||||
|
|
||||||
function decodeBook(market, accInfo: AccountInfo<Buffer>): number[][] {
|
function decodeBook(market, accInfo: AccountInfo<Buffer>): number[][] {
|
||||||
if (market && accInfo?.data) {
|
if (market && accInfo?.data) {
|
||||||
|
@ -33,7 +32,7 @@ function decodeBook(market, accInfo: AccountInfo<Buffer>): number[][] {
|
||||||
market,
|
market,
|
||||||
BookSideLayout.decode(accInfo.data)
|
BookSideLayout.decode(accInfo.data)
|
||||||
)
|
)
|
||||||
return book.getL2(depth).map(([price, size]) => [price, size])
|
return book.getL2Ui(depth)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return []
|
return []
|
||||||
|
|
|
@ -250,7 +250,7 @@
|
||||||
"open-interest": "Open Interest",
|
"open-interest": "Open Interest",
|
||||||
"open-orders": "Open Orders",
|
"open-orders": "Open Orders",
|
||||||
"optional": "(Optional)",
|
"optional": "(Optional)",
|
||||||
"oracle-price": "Oracle price",
|
"oracle-price": "Oracle Price",
|
||||||
"order-error": "Error placing order",
|
"order-error": "Error placing order",
|
||||||
"orderbook": "Orderbook",
|
"orderbook": "Orderbook",
|
||||||
"orderbook-animation": "Orderbook Animation",
|
"orderbook-animation": "Orderbook Animation",
|
||||||
|
|
|
@ -56,7 +56,7 @@ module.exports = {
|
||||||
'fgd-2': '#C8C8C8',
|
'fgd-2': '#C8C8C8',
|
||||||
'fgd-3': '#B3B3B3',
|
'fgd-3': '#B3B3B3',
|
||||||
'fgd-4': '#878787',
|
'fgd-4': '#878787',
|
||||||
'bkg-button': '#52514E',
|
'bkg-button': '#4E5152',
|
||||||
},
|
},
|
||||||
'mango-theme': {
|
'mango-theme': {
|
||||||
yellow: {
|
yellow: {
|
||||||
|
|
|
@ -12,8 +12,8 @@ export async function sleep(ms) {
|
||||||
|
|
||||||
export const percentFormat = new Intl.NumberFormat(undefined, {
|
export const percentFormat = new Intl.NumberFormat(undefined, {
|
||||||
style: 'percent',
|
style: 'percent',
|
||||||
minimumFractionDigits: 2,
|
minimumFractionDigits: 1,
|
||||||
maximumFractionDigits: 2,
|
maximumFractionDigits: 3,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function floorToDecimal(
|
export function floorToDecimal(
|
||||||
|
@ -41,6 +41,9 @@ export function roundToDecimal(
|
||||||
return decimals ? Math.round(value * 10 ** decimals) / 10 ** decimals : value
|
return decimals ? Math.round(value * 10 ** decimals) / 10 ** decimals : value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPrecisionDigits(x: number): number {
|
||||||
|
return -Math.round(Math.log10(x))
|
||||||
|
}
|
||||||
export function getDecimalCount(value): number {
|
export function getDecimalCount(value): number {
|
||||||
if (
|
if (
|
||||||
!isNaN(value) &&
|
!isNaN(value) &&
|
||||||
|
|
37
yarn.lock
37
yarn.lock
|
@ -1659,13 +1659,14 @@
|
||||||
resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.20.1.tgz#0937807e807e8332aa708cfef4bcb6cbb88b4129"
|
resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.20.1.tgz#0937807e807e8332aa708cfef4bcb6cbb88b4129"
|
||||||
integrity sha512-2TuBmGUn9qeYz6sJINJlElrBuPsaUAtYyUsJ3XplEBf1pczrANAgs5ceJUFzdiqGEWLn+84ObSdBeChT/AXYFA==
|
integrity sha512-2TuBmGUn9qeYz6sJINJlElrBuPsaUAtYyUsJ3XplEBf1pczrANAgs5ceJUFzdiqGEWLn+84ObSdBeChT/AXYFA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@project-serum/borsh" "^0.2.2"
|
"@project-serum/borsh" "^0.2.4"
|
||||||
"@solana/web3.js" "^1.17.0"
|
"@solana/web3.js" "^1.17.0"
|
||||||
base64-js "^1.5.1"
|
base64-js "^1.5.1"
|
||||||
bn.js "^5.1.2"
|
bn.js "^5.1.2"
|
||||||
bs58 "^4.0.1"
|
bs58 "^4.0.1"
|
||||||
buffer-layout "^1.2.2"
|
buffer-layout "^1.2.2"
|
||||||
camelcase "^5.3.1"
|
camelcase "^5.3.1"
|
||||||
|
cross-fetch "^3.1.5"
|
||||||
crypto-hash "^1.3.0"
|
crypto-hash "^1.3.0"
|
||||||
eventemitter3 "^4.0.7"
|
eventemitter3 "^4.0.7"
|
||||||
find "^0.3.0"
|
find "^0.3.0"
|
||||||
|
@ -1825,7 +1826,27 @@
|
||||||
buffer-layout "^1.2.0"
|
buffer-layout "^1.2.0"
|
||||||
dotenv "10.0.0"
|
dotenv "10.0.0"
|
||||||
|
|
||||||
"@solana/web3.js@^1.17.0", "@solana/web3.js@^1.21.0", "@solana/web3.js@^1.31.0":
|
"@solana/web3.js@^1.17.0", "@solana/web3.js@^1.21.0":
|
||||||
|
version "1.35.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.35.0.tgz#a2d09add241f48a370470a5c4db8596cb13f0dc6"
|
||||||
|
integrity sha512-eKf2rPoWEyVq7QsgAQKNqxODvPsb0vqSwwg2xRY1e49Fn5Qh29m2FiLcYHRS/xhPu/7b/5gsD+RzO3BWozOeZQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.5"
|
||||||
|
"@ethersproject/sha2" "^5.5.0"
|
||||||
|
"@solana/buffer-layout" "^3.0.0"
|
||||||
|
bn.js "^5.0.0"
|
||||||
|
borsh "^0.4.0"
|
||||||
|
bs58 "^4.0.1"
|
||||||
|
buffer "6.0.1"
|
||||||
|
cross-fetch "^3.1.4"
|
||||||
|
jayson "^3.4.4"
|
||||||
|
js-sha3 "^0.8.0"
|
||||||
|
rpc-websockets "^7.4.2"
|
||||||
|
secp256k1 "^4.0.2"
|
||||||
|
superstruct "^0.14.2"
|
||||||
|
tweetnacl "^1.0.0"
|
||||||
|
|
||||||
|
"@solana/web3.js@^1.31.0":
|
||||||
version "1.34.0"
|
version "1.34.0"
|
||||||
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.34.0.tgz#33becf2c7e87497d73406374185e54e0b7bc235d"
|
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.34.0.tgz#33becf2c7e87497d73406374185e54e0b7bc235d"
|
||||||
integrity sha512-6QvqN2DqEELvuV+5yUQM8P9fRiSG+6SzQ58HjumJqODu14r7eu5HXVWEymvKAvMLGME+0TmAdJHjw9xD5NgUWA==
|
integrity sha512-6QvqN2DqEELvuV+5yUQM8P9fRiSG+6SzQ58HjumJqODu14r7eu5HXVWEymvKAvMLGME+0TmAdJHjw9xD5NgUWA==
|
||||||
|
@ -2206,14 +2227,14 @@
|
||||||
integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==
|
integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*":
|
||||||
version "17.0.17"
|
version "17.0.18"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.17.tgz#a8ddf6e0c2341718d74ee3dc413a13a042c45a0c"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.18.tgz#3b4fed5cfb58010e3a2be4b6e74615e4847f1074"
|
||||||
integrity sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw==
|
integrity sha512-eKj4f/BsN/qcculZiRSujogjvp5O/k4lOW5m35NopjZM/QwLOR075a8pJW5hD+Rtdm2DaCVPENS6KtSQnUD6BA==
|
||||||
|
|
||||||
"@types/node@^12.12.54":
|
"@types/node@^12.12.54":
|
||||||
version "12.20.45"
|
version "12.20.46"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.45.tgz#f4980d177999299d99cd4b290f7f39366509a44f"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.46.tgz#7e49dee4c54fd19584e6a9e0da5f3dc2e9136bc7"
|
||||||
integrity sha512-1Jg2Qv5tuxBqgQV04+wO5u+wmSHbHgpORCJdeCLM+E+YdPElpdHhgywU+M1V1InL8rfOtpqtOjswk+uXTKwx7w==
|
integrity sha512-cPjLXj8d6anFPzFvOPxS3fvly3Shm5nTfl6g8X5smexixbuGUf7hfr21J5tX9JW+UPStp/5P5R8qrKL5IyVJ+A==
|
||||||
|
|
||||||
"@types/node@^14.14.25":
|
"@types/node@^14.14.25":
|
||||||
version "14.18.11"
|
version "14.18.11"
|
||||||
|
|
Loading…
Reference in New Issue