add openbook history
This commit is contained in:
parent
50fc7593ec
commit
59b724e431
|
@ -126,6 +126,7 @@ const ReadOnlyMangoAccount = () => {
|
|||
state.mangoAccount.current = readOnlyMangoAccount
|
||||
state.mangoAccount.initialLoad = false
|
||||
})
|
||||
actions.fetchTradeHistory()
|
||||
} catch (error) {
|
||||
console.error('error', error)
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ const MangoAccountsListModal = ({
|
|||
try {
|
||||
const reloadedMangoAccount = await retryFn(() => acc.reload(client))
|
||||
actions.fetchOpenOrders(reloadedMangoAccount)
|
||||
actions.fetchTradeHistory()
|
||||
|
||||
set((s) => {
|
||||
s.mangoAccount.current = reloadedMangoAccount
|
||||
|
|
|
@ -65,7 +65,9 @@ export const TableDateDisplay = ({
|
|||
showSeconds?: boolean
|
||||
}) => (
|
||||
<>
|
||||
<p className="text-th-fgd-2">{dayjs(date).format('DD MMM YYYY')}</p>
|
||||
<p className="tracking-normal text-th-fgd-2">
|
||||
{dayjs(date).format('DD MMM YYYY')}
|
||||
</p>
|
||||
<p className="text-xs text-th-fgd-4">
|
||||
{dayjs(date).format(showSeconds ? 'h:mm:ssa' : 'h:mma')}
|
||||
</p>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { I80F48, PerpMarket } from '@blockworks-foundation/mango-v4'
|
||||
import InlineNotification from '@components/shared/InlineNotification'
|
||||
import SideBadge from '@components/shared/SideBadge'
|
||||
import {
|
||||
Table,
|
||||
|
@ -10,6 +9,7 @@ import {
|
|||
TrHead,
|
||||
} from '@components/shared/TableElements'
|
||||
import { NoSymbolIcon } from '@heroicons/react/20/solid'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useSelectedMarket from 'hooks/useSelectedMarket'
|
||||
|
@ -86,27 +86,32 @@ const formatTradeHistory = (
|
|||
}
|
||||
|
||||
const TradeHistory = () => {
|
||||
const group = mangoStore.getState().group
|
||||
const { selectedMarket } = useSelectedMarket()
|
||||
const { mangoAccount, mangoAccountAddress } = useMangoAccount()
|
||||
const fills = mangoStore((s) => s.selectedMarket.fills)
|
||||
const tradeHistory = mangoStore((s) => s.mangoAccount.tradeHistory)
|
||||
const { width } = useViewport()
|
||||
const showTableView = width ? width > breakpoints.md : false
|
||||
|
||||
const openOrderOwner = useMemo(() => {
|
||||
if (!mangoAccount || !selectedMarket) return
|
||||
try {
|
||||
if (selectedMarket instanceof PerpMarket) {
|
||||
return mangoAccount.publicKey
|
||||
} else {
|
||||
try {
|
||||
return mangoAccount.getSerum3OoAccount(selectedMarket.marketIndex)
|
||||
.address
|
||||
} catch {
|
||||
console.warn(
|
||||
'Unable to find OO account for mkt index',
|
||||
selectedMarket.marketIndex
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error loading open order account for trade history: ', e)
|
||||
}
|
||||
}, [mangoAccount, selectedMarket])
|
||||
|
||||
const tradeHistoryFromEventQueue = useMemo(() => {
|
||||
const eventQueueFillsForAccount = useMemo(() => {
|
||||
if (!mangoAccountAddress || !selectedMarket) return []
|
||||
|
||||
const mangoAccountFills = fills
|
||||
|
@ -127,9 +132,30 @@ const TradeHistory = () => {
|
|||
return formatTradeHistory(mangoAccountAddress, mangoAccountFills)
|
||||
}, [selectedMarket, mangoAccountAddress, openOrderOwner, fills])
|
||||
|
||||
if (!selectedMarket) return null
|
||||
const combinedTradeHistory = useMemo(() => {
|
||||
let newFills = []
|
||||
if (eventQueueFillsForAccount?.length) {
|
||||
console.log('eventQueueFillsForAccount', eventQueueFillsForAccount)
|
||||
|
||||
return mangoAccount && tradeHistoryFromEventQueue.length ? (
|
||||
newFills = eventQueueFillsForAccount.filter((fill) => {
|
||||
return !tradeHistory.find((t) => {
|
||||
if (t.order_id) {
|
||||
return t.order_id === fill.orderId?.toString()
|
||||
}
|
||||
// else {
|
||||
// return t.seq_num === fill.seqNum?.toString()
|
||||
// }
|
||||
})
|
||||
})
|
||||
}
|
||||
return [...newFills, ...tradeHistory]
|
||||
}, [eventQueueFillsForAccount, tradeHistory])
|
||||
|
||||
console.log('trade history', tradeHistory)
|
||||
|
||||
if (!selectedMarket || !group) return null
|
||||
|
||||
return mangoAccount && combinedTradeHistory.length ? (
|
||||
showTableView ? (
|
||||
<div>
|
||||
<Table>
|
||||
|
@ -141,17 +167,31 @@ const TradeHistory = () => {
|
|||
<Th className="text-right">Price</Th>
|
||||
<Th className="text-right">Value</Th>
|
||||
<Th className="text-right">Fee</Th>
|
||||
{selectedMarket instanceof PerpMarket ? (
|
||||
<Th className="text-right">Time</Th>
|
||||
) : null}
|
||||
</TrHead>
|
||||
</thead>
|
||||
<tbody>
|
||||
{tradeHistoryFromEventQueue.map((trade: any) => {
|
||||
{combinedTradeHistory.map((trade: any) => {
|
||||
let market
|
||||
if ('market' in trade) {
|
||||
market = group.getSerum3MarketByExternalMarket(
|
||||
new PublicKey(trade.market)
|
||||
)
|
||||
} else {
|
||||
market = selectedMarket
|
||||
}
|
||||
let makerTaker = trade.liquidity
|
||||
if ('maker' in trade) {
|
||||
makerTaker = trade.maker ? 'Maker' : 'Taker'
|
||||
}
|
||||
|
||||
return (
|
||||
<TrBody key={`${trade.marketIndex}`} className="my-1 p-2">
|
||||
<TrBody
|
||||
key={`${trade.signature || trade.marketIndex}${trade.size}`}
|
||||
className="my-1 p-2"
|
||||
>
|
||||
<Td className="">
|
||||
<TableMarketName market={selectedMarket} />
|
||||
<TableMarketName market={market} />
|
||||
</Td>
|
||||
<Td className="text-right">
|
||||
<SideBadge side={trade.side} />
|
||||
|
@ -161,37 +201,36 @@ const TradeHistory = () => {
|
|||
{formatDecimal(trade.price)}
|
||||
</Td>
|
||||
<Td className="text-right font-mono">
|
||||
${trade.value.toFixed(2)}
|
||||
{trade.price * trade.size}
|
||||
</Td>
|
||||
<Td className="text-right">
|
||||
<span className="font-mono">{trade.feeCost}</span>
|
||||
<p className="font-body text-xs text-th-fgd-4">{`${
|
||||
trade.liquidity ? trade.liquidity : ''
|
||||
}`}</p>
|
||||
<span className="font-mono">
|
||||
{trade.fee_cost || trade.feeCost}
|
||||
</span>
|
||||
<p className="font-body text-xs text-th-fgd-4">
|
||||
{makerTaker}
|
||||
</p>
|
||||
</Td>
|
||||
{selectedMarket instanceof PerpMarket ? (
|
||||
<Td className="whitespace-nowrap text-right font-mono">
|
||||
|
||||
<Td className="whitespace-nowrap text-right">
|
||||
{trade.block_datetime ? (
|
||||
<TableDateDisplay
|
||||
date={trade.timestamp.toNumber() * 1000}
|
||||
date={trade.block_datetime}
|
||||
showSeconds
|
||||
/>
|
||||
) : (
|
||||
'Recent'
|
||||
)}
|
||||
</Td>
|
||||
) : null}
|
||||
</TrBody>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</Table>
|
||||
<div className="px-6 py-4">
|
||||
<InlineNotification
|
||||
type="info"
|
||||
desc="During the Mango V4 alpha, only your recent Openbook trades will be displayed here. Full trade history will be available shortly."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
{tradeHistoryFromEventQueue.map((trade: any) => {
|
||||
{eventQueueFillsForAccount.map((trade: any) => {
|
||||
return (
|
||||
<div
|
||||
className="flex items-center justify-between border-b border-th-bkg-3 p-4"
|
||||
|
@ -220,14 +259,8 @@ const TradeHistory = () => {
|
|||
)
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center px-6 pb-8 pt-4">
|
||||
<div className="mb-8 w-full">
|
||||
<InlineNotification
|
||||
type="info"
|
||||
desc="During the Mango V4 alpha, only your recent Openbook trades will be displayed here. Full trade history will be available shortly."
|
||||
/>
|
||||
</div>
|
||||
<NoSymbolIcon className="mb-2 h-6 w-6 text-th-fgd-4" />
|
||||
<p>No trade history for {selectedMarket?.name}</p>
|
||||
<p>No trade history</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ const TradeInfoTabs = () => {
|
|||
|
||||
return (
|
||||
<div className="hide-scroll h-full overflow-y-scroll pb-5">
|
||||
<div className="hide-scroll sticky top-0 z-10 overflow-x-auto border-b border-th-bkg-3">
|
||||
<div className="hide-scroll sticky top-0 z-20 overflow-x-auto border-b border-th-bkg-3">
|
||||
<TabButtons
|
||||
activeValue={selectedTab}
|
||||
onChange={(tab: string) => setSelectedTab(tab)}
|
||||
|
|
|
@ -38,6 +38,7 @@ const ConnectedMenu = () => {
|
|||
await actions.fetchMangoAccounts(wallet.adapter as unknown as AnchorWallet)
|
||||
actions.fetchTourSettings(wallet.adapter.publicKey?.toString() as string)
|
||||
actions.fetchWalletTokens(wallet.adapter as unknown as AnchorWallet)
|
||||
actions.fetchTradeHistory()
|
||||
}
|
||||
|
||||
const handleDisconnect = useCallback(() => {
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
PerpOrder,
|
||||
PerpPosition,
|
||||
BookSide,
|
||||
FillEvent,
|
||||
} from '@blockworks-foundation/mango-v4'
|
||||
|
||||
import EmptyWallet from '../utils/wallet'
|
||||
|
@ -35,7 +36,7 @@ import {
|
|||
OUTPUT_TOKEN_DEFAULT,
|
||||
RPC_PROVIDER_KEY,
|
||||
} from '../utils/constants'
|
||||
import { OrderbookL2, SpotBalances } from 'types'
|
||||
import { OrderbookL2, SpotBalances, SpotTradeHistory } from 'types'
|
||||
import spotBalancesUpdater from './spotBalancesUpdater'
|
||||
import { PerpMarket } from '@blockworks-foundation/mango-v4/'
|
||||
import perpPositionsUpdater from './perpPositionsUpdater'
|
||||
|
@ -69,7 +70,7 @@ const emptyWallet = new EmptyWallet(Keypair.generate())
|
|||
const initMangoClient = (provider: AnchorProvider): MangoClient => {
|
||||
return MangoClient.connect(provider, CLUSTER, MANGO_V4_ID[CLUSTER], {
|
||||
// blockhashCommitment: 'confirmed',
|
||||
prioritizationFee: 2000,
|
||||
prioritizationFee: 10000,
|
||||
idsSource: 'get-program-accounts',
|
||||
postSendTxCallback: ({ txid }: { txid: string }) => {
|
||||
notify({
|
||||
|
@ -245,6 +246,7 @@ export type MangoStore = {
|
|||
initialLoad: boolean
|
||||
}
|
||||
}
|
||||
tradeHistory: SpotTradeHistory[]
|
||||
}
|
||||
mangoAccounts: MangoAccount[]
|
||||
markets: Serum3Market[] | undefined
|
||||
|
@ -262,7 +264,7 @@ export type MangoStore = {
|
|||
selectedMarket: {
|
||||
name: string
|
||||
current: Serum3Market | PerpMarket | undefined
|
||||
fills: any
|
||||
fills: (FillEvent | any)[]
|
||||
bidsAccount: BookSide | Orderbook | undefined
|
||||
asksAccount: BookSide | Orderbook | undefined
|
||||
orderbook: OrderbookL2
|
||||
|
@ -325,6 +327,7 @@ export type MangoStore = {
|
|||
) => Promise<void>
|
||||
fetchTokenStats: () => void
|
||||
fetchTourSettings: (walletPk: string) => void
|
||||
fetchTradeHistory: () => Promise<void>
|
||||
fetchWalletTokens: (wallet: Wallet) => Promise<void>
|
||||
connectMangoClientWithWallet: (wallet: WalletAdapter) => Promise<void>
|
||||
loadMarketFills: () => Promise<void>
|
||||
|
@ -377,6 +380,7 @@ const mangoStore = create<MangoStore>()(
|
|||
performance: { data: [], loading: false },
|
||||
swapHistory: { data: [], initialLoad: false },
|
||||
},
|
||||
tradeHistory: [],
|
||||
},
|
||||
mangoAccounts: [],
|
||||
markets: undefined,
|
||||
|
@ -997,6 +1001,24 @@ const mangoStore = create<MangoStore>()(
|
|||
console.log('Error fetching fills:', err)
|
||||
}
|
||||
},
|
||||
async fetchTradeHistory() {
|
||||
const set = get().set
|
||||
// const selectedMarket = get().selectedMarket.current
|
||||
// const group = get().group
|
||||
const mangoAccount = get().mangoAccount.current
|
||||
|
||||
try {
|
||||
const res = await fetch(
|
||||
`https://mango-transaction-log.herokuapp.com/v4/stats/openbook-trades?address=${mangoAccount?.publicKey.toString()}&address-type=mango-account`
|
||||
)
|
||||
const parsedRes = await res.json()
|
||||
set((s) => {
|
||||
s.mangoAccount.tradeHistory = parsedRes.reverse()
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('Unable to fetch trade history', e)
|
||||
}
|
||||
},
|
||||
updateConnection(endpointUrl) {
|
||||
const set = get().set
|
||||
const client = mangoStore.getState().client
|
||||
|
|
|
@ -23,3 +23,25 @@ export type SpotBalances = Record<
|
|||
string,
|
||||
{ inOrders: number; unsettled: number }
|
||||
>
|
||||
|
||||
export interface SpotTradeHistory {
|
||||
signature: string
|
||||
block_datetime: string
|
||||
market: string
|
||||
open_orders: string
|
||||
mango_account: string
|
||||
bid: boolean
|
||||
maker: boolean
|
||||
referrer_rebate: any
|
||||
order_id: string
|
||||
client_order_id: string
|
||||
fee_tier: number
|
||||
instruction_num: number
|
||||
size: number
|
||||
price: number
|
||||
side: string
|
||||
fee_cost: number
|
||||
open_orders_owner: string
|
||||
base_symbol: string
|
||||
quote_symbol: string
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue