Merge pull request #258 from blockworks-foundation/toggle-orderbook-size-units

toggle orderbook size between base and quote
This commit is contained in:
saml33 2023-09-11 10:15:47 +10:00 committed by GitHub
commit 160b5fd9c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 104 additions and 15 deletions

View File

@ -17,7 +17,11 @@ import Decimal from 'decimal.js'
import Tooltip from '@components/shared/Tooltip' import Tooltip from '@components/shared/Tooltip'
import GroupSize from './GroupSize' import GroupSize from './GroupSize'
// import { useViewport } from 'hooks/useViewport' // import { useViewport } from 'hooks/useViewport'
import { BookSide, Serum3Market } from '@blockworks-foundation/mango-v4' import {
BookSide,
PerpMarket,
Serum3Market,
} from '@blockworks-foundation/mango-v4'
import useSelectedMarket from 'hooks/useSelectedMarket' import useSelectedMarket from 'hooks/useSelectedMarket'
import { INITIAL_ANIMATION_SETTINGS } from '@components/settings/AnimationSettings' import { INITIAL_ANIMATION_SETTINGS } from '@components/settings/AnimationSettings'
import { OrderbookFeed } from '@blockworks-foundation/mango-feeds' import { OrderbookFeed } from '@blockworks-foundation/mango-feeds'
@ -33,6 +37,7 @@ import {
import { OrderbookData, OrderbookL2 } from 'types' import { OrderbookData, OrderbookL2 } from 'types'
import isEqual from 'lodash/isEqual' import isEqual from 'lodash/isEqual'
import { useViewport } from 'hooks/useViewport' import { useViewport } from 'hooks/useViewport'
import TokenLogo from '@components/shared/TokenLogo'
const sizeCompacter = Intl.NumberFormat('en', { const sizeCompacter = Intl.NumberFormat('en', {
maximumFractionDigits: 6, maximumFractionDigits: 6,
@ -51,6 +56,7 @@ const Orderbook = () => {
const [useOrderbookFeed, setUseOrderbookFeed] = useState(false) const [useOrderbookFeed, setUseOrderbookFeed] = useState(false)
const orderbookElRef = useRef<HTMLDivElement>(null) const orderbookElRef = useRef<HTMLDivElement>(null)
const [isScrolled, setIsScrolled] = useState(false) const [isScrolled, setIsScrolled] = useState(false)
const [sizeInBase, setSizeInBase] = useState(true)
// const [useOrderbookFeed, setUseOrderbookFeed] = useState( // const [useOrderbookFeed, setUseOrderbookFeed] = useState(
// localStorage.getItem(USE_ORDERBOOK_FEED_KEY) !== null // localStorage.getItem(USE_ORDERBOOK_FEED_KEY) !== null
// ? localStorage.getItem(USE_ORDERBOOK_FEED_KEY) === 'true' // ? localStorage.getItem(USE_ORDERBOOK_FEED_KEY) === 'true'
@ -60,6 +66,23 @@ const Orderbook = () => {
const [orderbookData, setOrderbookData] = useState<OrderbookData | null>(null) const [orderbookData, setOrderbookData] = useState<OrderbookData | null>(null)
const currentOrderbookData = useRef<OrderbookL2>() const currentOrderbookData = useRef<OrderbookL2>()
const [baseBank, quoteBank] = useMemo(() => {
const { group } = mangoStore.getState()
if (!market || !group) return [undefined, undefined]
if (market instanceof PerpMarket) {
const baseTokenName = market.name.split('-')[0]
const base = group.banksMapByName.get(baseTokenName)?.[0]
const quote = group.getFirstBankByTokenIndex(market.settleTokenIndex)
return [base, quote]
} else {
const base = group.getFirstBankByMint(market.baseMintAddress)
const quote = group.getFirstBankByMint(market.quoteMintAddress)
return [base, quote]
}
}, [market])
console.log(baseBank, quoteBank)
const depth = useMemo(() => { const depth = useMemo(() => {
return isDesktop ? 30 : 12 return isDesktop ? 30 : 12
}, [isDesktop]) }, [isDesktop])
@ -454,7 +477,7 @@ const Orderbook = () => {
return ( return (
<div className="flex h-full flex-col"> <div className="flex h-full flex-col">
<div className="flex h-10 items-center justify-between border-b border-th-bkg-3 px-4"> <div className="flex h-8 items-center justify-between border-b border-th-bkg-3 px-4">
{market ? ( {market ? (
<> <>
<p className="text-xs">{t('trade:grouping')}:</p> <p className="text-xs">{t('trade:grouping')}:</p>
@ -475,9 +498,43 @@ const Orderbook = () => {
</> </>
) : null} ) : null}
</div> </div>
<div className="grid grid-cols-2 px-2 py-0.5 text-xxs text-th-fgd-4"> <div className="grid grid-cols-2 px-2 pb-1 pt-1.5 text-xxs text-th-fgd-4">
<div className="col-span-1">{t('price')}</div> <div className="col-span-1">{t('price')}</div>
<div className="col-span-1 text-right">{t('trade:size')}</div> <div className="col-span-1 flex items-center justify-end space-x-2">
<span className="text-right">{t('trade:size')}</span>
{baseBank && quoteBank ? (
<div className="flex h-[18px] space-x-1">
<Tooltip
content={t('trade:tooltip-size-base-quote', {
token: baseBank.name,
})}
>
<button
className={`rounded border p-0.5 ${
sizeInBase ? 'border-th-fgd-2' : 'border-th-bkg-4'
} focus:outline-none focus-visible:border-th-active md:hover:border-th-fgd-2`}
onClick={() => setSizeInBase(true)}
>
<TokenLogo bank={baseBank} size={12} />
</button>
</Tooltip>
<Tooltip
content={t('trade:tooltip-size-base-quote', {
token: quoteBank.name,
})}
>
<button
className={`rounded border p-0.5 ${
!sizeInBase ? 'border-th-fgd-2' : 'border-th-bkg-4'
} focus:outline-none focus-visible:border-th-active md:hover:border-th-fgd-2`}
onClick={() => setSizeInBase(false)}
>
<TokenLogo bank={quoteBank} size={12} />
</button>
</Tooltip>
</div>
) : null}
</div>
</div> </div>
<div <div
className="hide-scroll relative h-full overflow-y-scroll" className="hide-scroll relative h-full overflow-y-scroll"
@ -511,6 +568,7 @@ const Orderbook = () => {
orderbookData?.asks[index].cumulativeSizePercent orderbookData?.asks[index].cumulativeSizePercent
} }
grouping={grouping} grouping={grouping}
sizeInBase={sizeInBase}
/> />
) : null} ) : null}
</div> </div>
@ -559,6 +617,7 @@ const Orderbook = () => {
orderbookData?.bids[index].cumulativeSizePercent orderbookData?.bids[index].cumulativeSizePercent
} }
grouping={grouping} grouping={grouping}
sizeInBase={sizeInBase}
/> />
) : null} ) : null}
</div> </div>
@ -582,6 +641,7 @@ const OrderbookRow = ({
cumulativeSizePercent, cumulativeSizePercent,
tickSize, tickSize,
grouping, grouping,
sizeInBase,
}: { }: {
side: 'buy' | 'sell' side: 'buy' | 'sell'
price: number price: number
@ -596,6 +656,7 @@ const OrderbookRow = ({
grouping: number grouping: number
minOrderSize: number minOrderSize: number
tickSize: number tickSize: number
sizeInBase: boolean
}) => { }) => {
const element = useRef<HTMLDivElement>(null) const element = useRef<HTMLDivElement>(null)
const [animationSettings] = useLocalStorageState( const [animationSettings] = useLocalStorageState(
@ -618,10 +679,21 @@ const OrderbookRow = ({
}, [price, size]) }, [price, size])
const formattedSize = useMemo(() => { const formattedSize = useMemo(() => {
return minOrderSize && !isNaN(size) if (!minOrderSize || isNaN(size)) return new Decimal(size ?? -1)
? floorToDecimal(size, getDecimalCount(minOrderSize)) const sizeToShow = sizeInBase
: new Decimal(size ?? -1) ? size
}, [size, minOrderSize]) : new Decimal(size).mul(new Decimal(price)).toNumber()
const decimals = sizeInBase
? getDecimalCount(minOrderSize)
: getDecimalCount(tickSize)
return floorToDecimal(sizeToShow, decimals)
}, [minOrderSize, price, size, sizeInBase, tickSize])
// const formattedSize = useMemo(() => {
// return minOrderSize && !isNaN(size)
// ? floorToDecimal(size, getDecimalCount(minOrderSize))
// : new Decimal(size ?? -1)
// }, [size, minOrderSize, sizeInBase, tickSize])
const formattedPrice = useMemo(() => { const formattedPrice = useMemo(() => {
return tickSize && !isNaN(price) return tickSize && !isNaN(price)
@ -647,16 +719,28 @@ const OrderbookRow = ({
const handleSizeClick = useCallback(() => { const handleSizeClick = useCallback(() => {
const set = mangoStore.getState().set const set = mangoStore.getState().set
set((state) => { set((state) => {
state.tradeForm.baseSize = formattedSize.toString() if (sizeInBase) {
state.tradeForm.baseSize = formattedSize.toString()
} else {
state.tradeForm.quoteSize = formattedSize.toString()
}
if (formattedSize && state.tradeForm.price) { if (formattedSize && state.tradeForm.price) {
const quoteSize = floorToDecimal( if (sizeInBase) {
formattedSize.mul(new Decimal(state.tradeForm.price)), const quoteSize = floorToDecimal(
getDecimalCount(tickSize), formattedSize.mul(new Decimal(state.tradeForm.price)),
) getDecimalCount(tickSize),
state.tradeForm.quoteSize = quoteSize.toString() )
state.tradeForm.quoteSize = quoteSize.toString()
} else {
const baseSize = floorToDecimal(
formattedSize.div(new Decimal(state.tradeForm.price)),
getDecimalCount(minOrderSize),
)
state.tradeForm.baseSize = baseSize.toString()
}
} }
}) })
}, [formattedSize, tickSize]) }, [formattedSize, minOrderSize, size, sizeInBase, tickSize])
const groupingDecimalCount = useMemo( const groupingDecimalCount = useMemo(
() => getDecimalCount(grouping), () => getDecimalCount(grouping),

View File

@ -106,6 +106,7 @@
"tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled", "tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled",
"tooltip-insured": "Whether or not {{tokenOrMarket}} losses can be recovered from the insurance fund in the event of bankruptcies.", "tooltip-insured": "Whether or not {{tokenOrMarket}} losses can be recovered from the insurance fund in the event of bankruptcies.",
"tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled", "tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled",
"tooltip-size-base-quote": "Show size in {{token}}",
"tooltip-private-counterparty": "Counterparty has Private Account enabled", "tooltip-private-counterparty": "Counterparty has Private Account enabled",
"tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at", "tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at",
"tooltip-stable-price": "Stable price is used in a safety mechanism that limits a user's ability to enter risky positions when the oracle price is changing rapidly", "tooltip-stable-price": "Stable price is used in a safety mechanism that limits a user's ability to enter risky positions when the oracle price is changing rapidly",

View File

@ -106,6 +106,7 @@
"tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled", "tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled",
"tooltip-insured": "Whether or not {{tokenOrMarket}} losses can be recovered from the insurance fund in the event of bankruptcies.", "tooltip-insured": "Whether or not {{tokenOrMarket}} losses can be recovered from the insurance fund in the event of bankruptcies.",
"tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled", "tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled",
"tooltip-size-base-quote": "Show size in {{token}}",
"tooltip-private-counterparty": "Counterparty has Private Account enabled", "tooltip-private-counterparty": "Counterparty has Private Account enabled",
"tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at", "tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at",
"tooltip-stable-price": "Stable price is used in a safety mechanism that limits a user's ability to enter risky positions when the oracle price is changing rapidly", "tooltip-stable-price": "Stable price is used in a safety mechanism that limits a user's ability to enter risky positions when the oracle price is changing rapidly",

View File

@ -106,6 +106,7 @@
"tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled", "tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled",
"tooltip-insured": "Whether or not {{tokenOrMarket}} losses can be recovered from the insurance fund in the event of bankruptcies.", "tooltip-insured": "Whether or not {{tokenOrMarket}} losses can be recovered from the insurance fund in the event of bankruptcies.",
"tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled", "tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled",
"tooltip-size-base-quote": "Show size in {{token}}",
"tooltip-private-counterparty": "Counterparty has Private Account enabled", "tooltip-private-counterparty": "Counterparty has Private Account enabled",
"tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at", "tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at",
"tooltip-stable-price": "Stable price is used in a safety mechanism that limits a user's ability to enter risky positions when the oracle price is changing rapidly", "tooltip-stable-price": "Stable price is used in a safety mechanism that limits a user's ability to enter risky positions when the oracle price is changing rapidly",

View File

@ -111,6 +111,7 @@
"tooltip-insured": "如果发生破产,{{tokenOrMarket}}损失是否可以从保险基金中归还", "tooltip-insured": "如果发生破产,{{tokenOrMarket}}损失是否可以从保险基金中归还",
"tooltip-ioc": "IOC交易若不吃单就会被取消。任何无法立刻成交的部分将被取消", "tooltip-ioc": "IOC交易若不吃单就会被取消。任何无法立刻成交的部分将被取消",
"tooltip-post": "Post交易若不挂单就会被取消。", "tooltip-post": "Post交易若不挂单就会被取消。",
"tooltip-size-base-quote": "Show size in {{token}}",
"tooltip-private-counterparty": "Counterparty has Private Account enabled", "tooltip-private-counterparty": "Counterparty has Private Account enabled",
"tooltip-slippage": "当前价格与您的交易将执行的价格之间的差值的估计", "tooltip-slippage": "当前价格与您的交易将执行的价格之间的差值的估计",
"tooltip-stable-price": "稳定价格用于一个安全机制。此机制可以限制用户在预言机价格快速波动时下风险高的订单", "tooltip-stable-price": "稳定价格用于一个安全机制。此机制可以限制用户在预言机价格快速波动时下风险高的订单",

View File

@ -106,6 +106,7 @@
"tooltip-insured": "如果發生破產,{{tokenOrMarket}}損失是否可以從保險基金中歸還", "tooltip-insured": "如果發生破產,{{tokenOrMarket}}損失是否可以從保險基金中歸還",
"tooltip-ioc": "IOC交易若不吃單就會被取消。任何無法立刻成交的部分將被取消", "tooltip-ioc": "IOC交易若不吃單就會被取消。任何無法立刻成交的部分將被取消",
"tooltip-post": "Post交易若不掛單就會被取消。", "tooltip-post": "Post交易若不掛單就會被取消。",
"tooltip-size-base-quote": "Show size in {{token}}",
"tooltip-private-counterparty": "Counterparty has Private Account enabled", "tooltip-private-counterparty": "Counterparty has Private Account enabled",
"tooltip-slippage": "當前價格與您的交易將執行的價格之間的差值的估計", "tooltip-slippage": "當前價格與您的交易將執行的價格之間的差值的估計",
"tooltip-stable-price": "穩定價格用於一個安全機制。此機制可以限制用戶在預言機價格快速波動時下風險高的訂單", "tooltip-stable-price": "穩定價格用於一個安全機制。此機制可以限制用戶在預言機價格快速波動時下風險高的訂單",