mango-ui-v3/hooks/useTradeHistory.tsx

134 lines
3.9 KiB
TypeScript

import { getMarketByPublicKey } from '@blockworks-foundation/mango-client'
import { PublicKey } from '@solana/web3.js'
import useMangoStore from '../stores/useMangoStore'
const byTimestamp = (a, b) => {
return (
new Date(b.loadTimestamp || b.timestamp * 1000).getTime() -
new Date(a.loadTimestamp || a.timestamp * 1000).getTime()
)
}
const reverseSide = (side) => (side === 'buy' ? 'sell' : 'buy')
function getMarketName(event) {
const mangoGroupConfig = useMangoStore.getState().selectedMangoGroup.config
let marketName
if (!event.marketName && event.address) {
const marketInfo = getMarketByPublicKey(mangoGroupConfig, event.address)
marketName = marketInfo.name
}
return event.marketName || marketName
}
const parsedPerpEvent = (mangoAccountPk: PublicKey, event) => {
const maker = event.maker.toString() === mangoAccountPk.toString()
const orderId = maker ? event.makerOrderId : event.takerOrderId
const value = event.quantity * event.price
const feeRate = maker ? event.makerFee : event.takerFee
const side = maker ? reverseSide(event.takerSide) : event.takerSide
return {
...event,
key: orderId?.toString(),
liquidity: maker ? 'Maker' : 'Taker',
size: event.quantity,
price: event.price,
value,
feeCost: (feeRate * value).toFixed(4),
side,
marketName: getMarketName(event),
}
}
const parsedSerumEvent = (event) => {
let liquidity
if (event.eventFlags) {
liquidity = event?.eventFlags?.maker ? 'Maker' : 'Taker'
} else {
liquidity = event.maker ? 'Maker' : 'Taker'
}
return {
...event,
liquidity,
key: `${event.maker}-${event.price}`,
value: event.price * event.size,
side: event.side,
marketName: getMarketName(event),
}
}
const formatTradeHistory = (mangoAccountPk: PublicKey, newTradeHistory) => {
return newTradeHistory
.flat()
.map((event) => {
if (event.eventFlags || event.nativeQuantityPaid) {
return parsedSerumEvent(event)
} else if (event.maker) {
return parsedPerpEvent(mangoAccountPk, event)
} else {
return event
}
})
.sort(byTimestamp)
}
export const useTradeHistory = (
opts: { excludePerpLiquidations?: boolean } = {}
) => {
const marketConfig = useMangoStore((s) => s.selectedMarket.config)
const fills = useMangoStore((s) => s.selectedMarket.fills)
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
const selectedMangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
let tradeHistory = useMangoStore((s) => s.tradeHistory)
if (!mangoAccount || !selectedMangoGroup) return null
const openOrdersAccount =
mangoAccount.spotOpenOrdersAccounts[marketConfig.marketIndex]
const mangoAccountFills = fills
.filter((fill) => {
if (fill.openOrders) {
return openOrdersAccount?.publicKey
? fill.openOrders.equals(openOrdersAccount?.publicKey)
: false
} else {
return (
fill.taker.equals(mangoAccount.publicKey) ||
fill.maker.equals(mangoAccount.publicKey)
)
}
})
.map((fill) => ({ ...fill, marketName: marketConfig.name }))
const allTrades = []
if (mangoAccountFills && mangoAccountFills.length > 0) {
const newFills = mangoAccountFills.filter(
(fill) =>
!tradeHistory.flat().find((t) => {
if (t.orderId) {
return t.orderId === fill.orderId?.toString()
} else {
return t.seqNum === fill.seqNum?.toString()
}
})
)
const newTradeHistory = [...newFills, ...tradeHistory]
if (newFills.length > 0 && newTradeHistory.length !== allTrades.length) {
tradeHistory = newTradeHistory
}
}
const formattedTradeHistory = formatTradeHistory(
mangoAccount.publicKey,
tradeHistory
)
if (opts.excludePerpLiquidations) {
return formattedTradeHistory.filter((t) => !('liqor' in t))
}
return formattedTradeHistory
}
export default useTradeHistory