Merge branch 'tif' into main

This commit is contained in:
tjs 2022-02-28 12:52:08 -05:00
commit 6ff5517045
17 changed files with 274 additions and 185 deletions

View File

@ -59,6 +59,7 @@ export interface Balances extends BalancesBase {
value?: I80F48 | null | undefined
depositRate?: I80F48 | null | undefined
borrowRate?: I80F48 | null | undefined
decimals?: number | null | undefined
}
export interface OpenOrdersBalances extends BalancesBase {

View File

@ -1,31 +1,29 @@
import { useCallback } from 'react'
import { useCallback, useState } from 'react'
import { useBalances } from '../hooks/useBalances'
import useMangoStore from '../stores/useMangoStore'
import Button, { LinkButton } from '../components/Button'
import { notify } from '../utils/notifications'
import { ArrowSmDownIcon, ExclamationIcon } from '@heroicons/react/outline'
import { Market } from '@project-serum/serum'
import {
getMarketIndexBySymbol,
getTokenBySymbol,
} from '@blockworks-foundation/mango-client'
import { useState } from 'react'
import { getTokenBySymbol } from '@blockworks-foundation/mango-client'
import Loading from './Loading'
import { useViewport } from '../hooks/useViewport'
import { breakpoints } from './TradePageGrid'
import { floorToDecimal, formatUsdValue } from '../utils'
import { Table, Td, Th, TrBody, TrHead } from './TableElements'
import { floorToDecimal, formatUsdValue, getPrecisionDigits } from '../utils'
import { ExpandableRow, Table, Td, Th, TrBody, TrHead } from './TableElements'
import { useSortableData } from '../hooks/useSortableData'
import DepositModal from './DepositModal'
import WithdrawModal from './WithdrawModal'
import { ExpandableRow } from './TableElements'
import MobileTableHeader from './mobile/MobileTableHeader'
import { useTranslation } from 'next-i18next'
import { TransactionSignature } from '@solana/web3.js'
import Link from 'next/link'
import { useRouter } from 'next/router'
const BalancesTable = ({
showZeroBalances = false,
showDepositWithdraw = false,
clickToPopulateTradeForm = false,
}) => {
const { t } = useTranslation('common')
const [showDepositModal, setShowDepositModal] = useState(false)
@ -59,34 +57,42 @@ const BalancesTable = ({
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
const wallet = useMangoStore((s) => s.wallet.current)
const canWithdraw = mangoAccount?.owner.equals(wallet.publicKey)
const { asPath } = useRouter()
const handleSizeClick = (size, symbol) => {
const step = selectedMarket.minOrderSize
const marketIndex = getMarketIndexBySymbol(
mangoGroupConfig,
marketConfig.baseSymbol
)
const minOrderSize = selectedMarket.minOrderSize
const sizePrecisionDigits = getPrecisionDigits(minOrderSize)
const marketIndex = marketConfig.marketIndex
const priceOrDefault = price
? price
: mangoGroup.getPrice(marketIndex, mangoGroupCache).toNumber()
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'
})
}
}
: mangoGroup.getPriceUi(marketIndex, mangoGroupCache)
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) => {
setActionSymbol(symbol)
setShowDepositModal(true)
@ -158,6 +164,7 @@ const BalancesTable = ({
</div>
{unsettledBalances.map((bal) => {
const tokenConfig = getTokenBySymbol(mangoGroupConfig, bal.symbol)
return (
<div
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`}
/>
{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>
</Td>
<Td>{balance.deposits.toFixed()}</Td>
<Td>{balance.borrows.toFixed()}</Td>
<Td>
{balance.deposits.toLocaleString(undefined, {
maximumFractionDigits: balance.decimals,
})}
</Td>
<Td>
{balance.borrows.toLocaleString(undefined, {
maximumFractionDigits: balance.decimals,
})}
</Td>
<Td>{balance.orders}</Td>
<Td>{balance.unsettled}</Td>
<Td>
{marketConfig.kind === 'spot' &&
marketConfig.name.includes(balance.symbol) &&
selectedMarket ? (
selectedMarket &&
clickToPopulateTradeForm ? (
<span
className={
balance.net.toNumber() > 0
balance.net.toNumber() != 0
? 'cursor-pointer underline hover:no-underline'
: ''
}
@ -377,10 +410,14 @@ const BalancesTable = ({
handleSizeClick(balance.net, balance.symbol)
}
>
{balance.net.toFixed()}
{balance.net.toLocaleString(undefined, {
maximumFractionDigits: balance.decimals,
})}
</span>
) : (
balance.net.toFixed()
balance.net.toLocaleString(undefined, {
maximumFractionDigits: balance.decimals,
})
)}
</Td>
<Td>{formatUsdValue(balance.value.toNumber())}</Td>
@ -464,7 +501,9 @@ const BalancesTable = ({
{balance.symbol}
</div>
<div className="text-th-fgd-1 text-right">
{balance.net.toFixed()}
{balance.net.toLocaleString(undefined, {
maximumFractionDigits: balance.decimals,
})}
</div>
</div>
}
@ -477,25 +516,33 @@ const BalancesTable = ({
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('deposits')}
</div>
{balance.deposits.toFixed()}
{balance.deposits.toLocaleString(undefined, {
maximumFractionDigits: balance.decimals,
})}
</div>
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('borrows')}
</div>
{balance.borrows.toFixed()}
{balance.borrows.toLocaleString(undefined, {
maximumFractionDigits: balance.decimals,
})}
</div>
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('in-orders')}
</div>
{balance.orders.toFixed()}
{balance.orders.toLocaleString(undefined, {
maximumFractionDigits: balance.decimals,
})}
</div>
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('unsettled')}
</div>
{balance.unsettled.toFixed()}
{balance.unsettled.toLocaleString(undefined, {
maximumFractionDigits: balance.decimals,
})}
</div>
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
@ -544,7 +591,9 @@ const BalancesTable = ({
tokenSymbol={actionSymbol}
repayAmount={
balance.borrows.toNumber() > 0
? balance.borrows.toFixed()
? balance.borrows.toLocaleString(undefined, {
maximumFractionDigits: balance.decimals,
})
: ''
}
/>

View File

@ -1,11 +1,8 @@
import { ElementTitle } from './styles'
import useMangoStore from '../stores/useMangoStore'
import { i80f48ToPercent, floorToDecimal } from '../utils/index'
import { getPrecisionDigits, i80f48ToPercent } from '../utils'
import Tooltip from './Tooltip'
import {
getMarketIndexBySymbol,
nativeI80F48ToUi,
} from '@blockworks-foundation/mango-client'
import { nativeI80F48ToUi } from '@blockworks-foundation/mango-client'
import { useViewport } from '../hooks/useViewport'
import { breakpoints } from './TradePageGrid'
import { useTranslation } from 'next-i18next'
@ -27,30 +24,38 @@ export default function MarketBalances() {
const isMobile = width ? width < breakpoints.sm : false
const handleSizeClick = (size, symbol) => {
const step = selectedMarket.minOrderSize
const marketIndex = getMarketIndexBySymbol(
mangoGroupConfig,
marketConfig.baseSymbol
)
const minOrderSize = selectedMarket.minOrderSize
const sizePrecisionDigits = getPrecisionDigits(minOrderSize)
const marketIndex = marketConfig.marketIndex
const priceOrDefault = price
? price
: mangoGroup.getPrice(marketIndex, mangoGroupCache).toNumber()
: mangoGroup.getPriceUi(marketIndex, mangoGroupCache)
let roundedSize, side
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'
})
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 {
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'
})
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
})
}
if (!mangoGroup || !selectedMarket) return null
@ -67,31 +72,22 @@ export default function MarketBalances() {
.reverse()
.map(({ decimals, symbol, mintKey }) => {
const tokenIndex = mangoGroup.getTokenIndex(mintKey)
const deposit = mangoAccount
? mangoAccount.getUiDeposit(
mangoGroupCache.rootBankCache[tokenIndex],
mangoGroup,
tokenIndex
const balance = mangoAccount
? nativeI80F48ToUi(
mangoAccount.getNet(
mangoGroupCache.rootBankCache[tokenIndex],
tokenIndex
),
decimals
)
: null
const borrow = mangoAccount
? mangoAccount.getUiBorrow(
mangoGroupCache.rootBankCache[tokenIndex],
mangoGroup,
tokenIndex
)
: null
: 0
const availableBalance = mangoAccount
? floorToDecimal(
nativeI80F48ToUi(
mangoAccount.getAvailableBalance(
mangoGroup,
mangoGroupCache,
tokenIndex
),
decimals
).toNumber(),
? nativeI80F48ToUi(
mangoAccount.getAvailableBalance(
mangoGroup,
mangoGroupCache,
tokenIndex
),
decimals
)
: 0
@ -115,19 +111,20 @@ export default function MarketBalances() {
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('balance')}
</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 ? (
<DataLoader />
) : mangoAccount ? (
deposit.gt(borrow) ? (
deposit.toFixed()
) : borrow.toNumber() > 0 ? (
`-${borrow.toFixed()}`
) : (
0
)
) : (
0
balance.toLocaleString(undefined, {
maximumFractionDigits: decimals,
})
)}
</div>
</div>
@ -147,10 +144,10 @@ export default function MarketBalances() {
>
{isLoading ? (
<DataLoader />
) : mangoAccount ? (
availableBalance
) : (
0
availableBalance.toLocaleString(undefined, {
maximumFractionDigits: decimals,
})
)}
</div>
</div>

View File

@ -59,20 +59,20 @@ const MarketCloseModal: FunctionComponent<MarketCloseModalProps> = ({
// hard coded for now; market orders are very dangerous and fault prone
const maxSlippage: number | undefined = 0.025
const txid = await mangoClient.placePerpOrder(
const txid = await mangoClient.placePerpOrder2(
mangoGroup,
mangoAccount,
mangoGroup.mangoCache,
market,
wallet,
side,
referencePrice * (1 + (side === 'buy' ? 1 : -1) * maxSlippage),
size,
'ioc',
0, // client order id
side === 'buy' ? askInfo : bidInfo,
true, // reduce only
referrerPk ? referrerPk : undefined
{
orderType: 'ioc',
bookSideInfo: side === 'buy' ? askInfo : bidInfo,
reduceOnly: true,
referrerMangoAccountPk: referrerPk ? referrerPk : undefined,
}
)
await sleep(500)
actions.reloadMangoAccount()

View File

@ -1,5 +1,5 @@
import React, { useCallback, useMemo, useState } from 'react'
import useMangoStore from '../stores/useMangoStore'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import useMangoStore, { SECONDS } from '../stores/useMangoStore'
import usePrevious from '../hooks/usePrevious'
import useInterval from '../hooks/useInterval'
import ChartApi from '../utils/chartDataConnector'
@ -7,10 +7,10 @@ import UiLock from './UiLock'
import ManualRefresh from './ManualRefresh'
import useOraclePrice from '../hooks/useOraclePrice'
import DayHighLow from './DayHighLow'
import { useEffect } from 'react'
import {
getDecimalCount,
getPrecisionDigits,
patchInternalMarketName,
perpContractPrecision,
usdFormatter,
} from '../utils'
import { PerpMarket } from '@blockworks-foundation/mango-client'
@ -20,7 +20,6 @@ import { breakpoints } from './TradePageGrid'
import { useTranslation } from 'next-i18next'
import SwitchMarketDropdown from './SwitchMarketDropdown'
import Tooltip from './Tooltip'
import { SECONDS } from '../stores/useMangoStore'
export function calculateFundingRate(perpStats, perpMarket) {
const oldestStat = perpStats[perpStats.length - 1]
@ -190,7 +189,11 @@ const MarketDetails = () => {
</div>
<div className="text-th-fgd-1 md:text-xs">
{oraclePrice && selectedMarket
? oraclePrice.toFixed(getDecimalCount(selectedMarket.tickSize))
? oraclePrice.toNumber().toLocaleString(undefined, {
maximumFractionDigits: getPrecisionDigits(
selectedMarket.tickSize
),
})
: '--'}
</div>
</div>
@ -255,7 +258,9 @@ const MarketDetails = () => {
{selectedMarket ? (
`${parseOpenInterest(
selectedMarket as PerpMarket
)} ${baseSymbol}`
).toLocaleString(undefined, {
maximumFractionDigits: perpContractPrecision[baseSymbol],
})} ${baseSymbol}`
) : (
<MarketDataLoader />
)}

View File

@ -1,7 +1,11 @@
import { useCallback, useMemo, useState } from 'react'
import { ElementTitle } from './styles'
import useMangoStore from '../stores/useMangoStore'
import { formatUsdValue } from '../utils/index'
import {
formatUsdValue,
getPrecisionDigits,
perpContractPrecision,
} from '../utils'
import Button, { LinkButton } from './Button'
import Tooltip from './Tooltip'
import PerpSideBadge from './PerpSideBadge'
@ -92,18 +96,17 @@ export default function MarketPosition() {
perpAccount = mangoAccount.perpAccounts[marketIndex]
}
const handleSizeClick = (size, side) => {
const step = selectedMarket.minOrderSize
const handleSizeClick = (size) => {
const sizePrecisionDigits = getPrecisionDigits(selectedMarket.minOrderSize)
const priceOrDefault = price
? price
: mangoGroup.getPrice(marketIndex, mangoCache).toNumber()
const roundedSize = Math.round(size / step) * step
const quoteSize = roundedSize * priceOrDefault
: mangoGroup.getPriceUi(marketIndex, mangoCache)
const roundedSize = parseFloat(Math.abs(size).toFixed(sizePrecisionDigits))
const quoteSize = parseFloat((roundedSize * priceOrDefault).toFixed(2))
setMangoStore((state) => {
state.tradeForm.baseSize = roundedSize
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 ? (
<span
className="cursor-pointer underline hover:no-underline"
onClick={() =>
handleSizeClick(
Math.abs(basePosition),
basePosition > 0 ? 'buy' : 'sell'
)
}
onClick={() => handleSizeClick(basePosition)}
>
{`${Math.abs(basePosition)} ${baseSymbol}`}
{`${Math.abs(basePosition).toLocaleString(undefined, {
maximumFractionDigits: perpContractPrecision[baseSymbol],
})} ${baseSymbol}`}
</span>
) : (
`0 ${baseSymbol}`

View File

@ -99,7 +99,11 @@ const DesktopTable = ({
</Td>
{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%]">
{usdFormatter(order.price, decimals)}
</Td>

View File

@ -9,7 +9,11 @@ import Button from '../components/Button'
import { useViewport } from '../hooks/useViewport'
import { breakpoints } from './TradePageGrid'
import { ExpandableRow, Table, Td, Th, TrBody, TrHead } from './TableElements'
import { formatUsdValue } from '../utils'
import {
formatUsdValue,
getPrecisionDigits,
perpContractPrecision,
} from '../utils'
import Loading from './Loading'
import MarketCloseModal from './MarketCloseModal'
import PerpSideBadge from './PerpSideBadge'
@ -40,15 +44,15 @@ const PositionsTable = () => {
setShowMarketCloseModal(false)
}, [])
const handleSizeClick = (size, side, indexPrice) => {
const step = selectedMarket.minOrderSize
const handleSizeClick = (size, indexPrice) => {
const sizePrecisionDigits = getPrecisionDigits(selectedMarket.minOrderSize)
const priceOrDefault = price ? price : indexPrice
const roundedSize = Math.round(size / step) * step
const quoteSize = roundedSize * priceOrDefault
const roundedSize = parseFloat(Math.abs(size).toFixed(sizePrecisionDigits))
const quoteSize = parseFloat((roundedSize * priceOrDefault).toFixed(2))
setMangoStore((state) => {
state.tradeForm.baseSize = roundedSize
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,
unrealizedPnl,
}) => {
const basePositionUi = Math.abs(
basePosition
).toLocaleString(undefined, {
maximumFractionDigits:
perpContractPrecision[marketConfig.baseSymbol],
})
return (
<TrBody key={`${marketConfig.marketIndex}`}>
<Td>
@ -169,22 +179,14 @@ const PositionsTable = () => {
<span
className="cursor-pointer underline hover:no-underline"
onClick={() =>
handleSizeClick(
Math.abs(basePosition),
basePosition > 0 ? 'buy' : 'sell',
indexPrice
)
handleSizeClick(basePosition, indexPrice)
}
>
{`${Math.abs(basePosition)} ${
marketConfig.baseSymbol
}`}
{`${basePositionUi} ${marketConfig.baseSymbol}`}
</span>
) : (
<span>
{`${Math.abs(basePosition)} ${
marketConfig.baseSymbol
}`}
{`${basePositionUi} ${marketConfig.baseSymbol}`}
</span>
)}
</Td>

View File

@ -55,7 +55,7 @@ const TabContent = ({ activeTab }) => {
case 'Orders':
return <OpenOrdersTable />
case 'Balances':
return <BalancesTable />
return <BalancesTable clickToPopulateTradeForm />
case 'Trade History':
return <TradeHistoryTable numTrades={100} />
case 'Positions':
@ -63,7 +63,7 @@ const TabContent = ({ activeTab }) => {
case 'Fee Discount':
return <FeeDiscountsTable />
default:
return <BalancesTable />
return <BalancesTable clickToPopulateTradeForm />
}
}

View File

@ -14,7 +14,11 @@ import {
InformationCircleIcon,
} from '@heroicons/react/outline'
import { notify } from '../../utils/notifications'
import { calculateTradePrice, getDecimalCount } from '../../utils'
import {
calculateTradePrice,
getDecimalCount,
percentFormat,
} from '../../utils'
import { floorToDecimal } from '../../utils/index'
import useMangoStore, { Orderbook } from '../../stores/useMangoStore'
import Button, { LinkButton } from '../Button'
@ -658,20 +662,21 @@ export default function AdvancedTradeForm({
)
actions.reloadOrders()
} else {
txid = await mangoClient.placePerpOrder(
txid = await mangoClient.placePerpOrder2(
mangoGroup,
mangoAccount,
mangoGroup.mangoCache,
market,
wallet,
side,
perpOrderPrice,
baseSize,
perpOrderType,
Date.now(),
side === 'buy' ? askInfo : bidInfo, // book side used for ConsumeEvents
reduceOnly,
referrerPk ? referrerPk : undefined
{
orderType: perpOrderType,
clientOrderId: Date.now(),
bookSideInfo: side === 'buy' ? askInfo : bidInfo, // book side used for ConsumeEvents
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>
{t('maker-fee')}: {(makerFee * 100).toFixed(2)}%{' '}
{t('maker-fee')}: {percentFormat.format(makerFee)}{' '}
</div>
<span className="hidden md:block md:px-1">|</span>
<div>
{' '}
{t('taker-fee')}: {(takerFee * 100).toFixed(3)}%
{t('taker-fee')}: {percentFormat.format(takerFee)}
</div>
</div>
)}

View File

@ -316,18 +316,18 @@ export default function SimpleTradeForm({ initLeverage }) {
orderType
)
} else {
txid = await mangoClient.placePerpOrder(
txid = await mangoClient.placePerpOrder2(
mangoGroup,
mangoAccount,
mangoGroup.mangoCache,
market,
wallet,
side,
orderPrice,
baseSize,
orderType,
0,
side === 'buy' ? askInfo : bidInfo
{
orderType,
bookSideInfo: side === 'buy' ? askInfo : bidInfo,
}
)
}
notify({ title: t('successfully-placed'), txid })

View File

@ -107,6 +107,7 @@ export function useBalances(): Balances[] {
value: value(nativeBaseLocked, tokenIndex),
depositRate: i80f48ToPercent(mangoGroup.getDepositRate(tokenIndex)),
borrowRate: i80f48ToPercent(mangoGroup.getBorrowRate(tokenIndex)),
decimals: mangoGroup.tokens[tokenIndex].decimals,
},
{
market: null,
@ -134,6 +135,7 @@ export function useBalances(): Balances[] {
value: value(nativeQuoteLocked, quoteCurrencyIndex),
depositRate: i80f48ToPercent(mangoGroup.getDepositRate(tokenIndex)),
borrowRate: i80f48ToPercent(mangoGroup.getBorrowRate(tokenIndex)),
decimals: mangoGroup.tokens[quoteCurrencyIndex].decimals,
},
]
balances.push(marketPair)
@ -172,6 +174,7 @@ export function useBalances(): Balances[] {
value,
depositRate,
borrowRate,
decimals: mangoGroup.tokens[QUOTE_INDEX].decimals,
},
].concat(baseBalances)
}

View File

@ -1,8 +1,8 @@
import { useEffect } from 'react'
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 { Orderbook as SpotOrderBook, Market } from '@project-serum/serum'
import { Market, Orderbook as SpotOrderBook } from '@project-serum/serum'
import {
BookSide,
BookSideLayout,
@ -19,7 +19,6 @@ import {
marketSelector,
marketsSelector,
} from '../stores/selectors'
import { SECONDS } from '../stores/useMangoStore'
function decodeBook(market, accInfo: AccountInfo<Buffer>): number[][] {
if (market && accInfo?.data) {
@ -33,7 +32,7 @@ function decodeBook(market, accInfo: AccountInfo<Buffer>): number[][] {
market,
BookSideLayout.decode(accInfo.data)
)
return book.getL2(depth).map(([price, size]) => [price, size])
return book.getL2Ui(depth)
}
} else {
return []

View File

@ -250,7 +250,7 @@
"open-interest": "Open Interest",
"open-orders": "Open Orders",
"optional": "(Optional)",
"oracle-price": "Oracle price",
"oracle-price": "Oracle Price",
"order-error": "Error placing order",
"orderbook": "Orderbook",
"orderbook-animation": "Orderbook Animation",

View File

@ -56,7 +56,7 @@ module.exports = {
'fgd-2': '#C8C8C8',
'fgd-3': '#B3B3B3',
'fgd-4': '#878787',
'bkg-button': '#52514E',
'bkg-button': '#4E5152',
},
'mango-theme': {
yellow: {

View File

@ -12,8 +12,8 @@ export async function sleep(ms) {
export const percentFormat = new Intl.NumberFormat(undefined, {
style: 'percent',
minimumFractionDigits: 2,
maximumFractionDigits: 2,
minimumFractionDigits: 1,
maximumFractionDigits: 3,
})
export function floorToDecimal(
@ -41,6 +41,9 @@ export function roundToDecimal(
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 {
if (
!isNaN(value) &&

View File

@ -1659,13 +1659,14 @@
resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.20.1.tgz#0937807e807e8332aa708cfef4bcb6cbb88b4129"
integrity sha512-2TuBmGUn9qeYz6sJINJlElrBuPsaUAtYyUsJ3XplEBf1pczrANAgs5ceJUFzdiqGEWLn+84ObSdBeChT/AXYFA==
dependencies:
"@project-serum/borsh" "^0.2.2"
"@project-serum/borsh" "^0.2.4"
"@solana/web3.js" "^1.17.0"
base64-js "^1.5.1"
bn.js "^5.1.2"
bs58 "^4.0.1"
buffer-layout "^1.2.2"
camelcase "^5.3.1"
cross-fetch "^3.1.5"
crypto-hash "^1.3.0"
eventemitter3 "^4.0.7"
find "^0.3.0"
@ -1825,7 +1826,27 @@
buffer-layout "^1.2.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"
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.34.0.tgz#33becf2c7e87497d73406374185e54e0b7bc235d"
integrity sha512-6QvqN2DqEELvuV+5yUQM8P9fRiSG+6SzQ58HjumJqODu14r7eu5HXVWEymvKAvMLGME+0TmAdJHjw9xD5NgUWA==
@ -2206,14 +2227,14 @@
integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==
"@types/node@*":
version "17.0.17"
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.17.tgz#a8ddf6e0c2341718d74ee3dc413a13a042c45a0c"
integrity sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw==
version "17.0.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.18.tgz#3b4fed5cfb58010e3a2be4b6e74615e4847f1074"
integrity sha512-eKj4f/BsN/qcculZiRSujogjvp5O/k4lOW5m35NopjZM/QwLOR075a8pJW5hD+Rtdm2DaCVPENS6KtSQnUD6BA==
"@types/node@^12.12.54":
version "12.20.45"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.45.tgz#f4980d177999299d99cd4b290f7f39366509a44f"
integrity sha512-1Jg2Qv5tuxBqgQV04+wO5u+wmSHbHgpORCJdeCLM+E+YdPElpdHhgywU+M1V1InL8rfOtpqtOjswk+uXTKwx7w==
version "12.20.46"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.46.tgz#7e49dee4c54fd19584e6a9e0da5f3dc2e9136bc7"
integrity sha512-cPjLXj8d6anFPzFvOPxS3fvly3Shm5nTfl6g8X5smexixbuGUf7hfr21J5tX9JW+UPStp/5P5R8qrKL5IyVJ+A==
"@types/node@^14.14.25":
version "14.18.11"