open orders are kinda adapted
This commit is contained in:
parent
3f3ffb1a37
commit
2c487348f6
|
@ -13,6 +13,8 @@ import { notify } from '../utils/notifications'
|
|||
import { Table, Thead, Tbody, Tr, Th, Td } from 'react-super-responsive-table'
|
||||
import SideBadge from './SideBadge'
|
||||
import { useSortableData } from '../hooks/useSortableData'
|
||||
import { Order, Market } from '@project-serum/serum/lib/market'
|
||||
import { Order as PerpOrder, PerpMarket } from '@blockworks-foundation/mango-client'
|
||||
|
||||
const OpenOrdersTable = () => {
|
||||
const { asPath } = useRouter()
|
||||
|
@ -22,22 +24,27 @@ const OpenOrdersTable = () => {
|
|||
// const { connection, programId } = useConnection()
|
||||
const actions = useMangoStore((s) => s.actions)
|
||||
|
||||
const handleCancelOrder = async (order) => {
|
||||
const handleCancelOrder = async (order: Order | PerpOrder, market: Market | PerpMarket) => {
|
||||
const wallet = useMangoStore.getState().wallet.current
|
||||
const selectedMangoGroup =
|
||||
useMangoStore.getState().selectedMangoGroup.current
|
||||
const selectedMarginAccount =
|
||||
useMangoStore.getState().selectedMarginAccount.current
|
||||
setCancelId(order?.orderId)
|
||||
setCancelId(order.orderId)
|
||||
|
||||
try {
|
||||
if (!selectedMangoGroup || !selectedMarginAccount) return
|
||||
if (market instanceof Market) {
|
||||
await mangoClient.cancelSpotOrder(
|
||||
selectedMangoGroup,
|
||||
selectedMarginAccount,
|
||||
wallet,
|
||||
order.market,
|
||||
order
|
||||
market,
|
||||
order as Order
|
||||
)
|
||||
} else if (market instanceof PerpMarket) {
|
||||
console.log('TBD');
|
||||
}
|
||||
actions.fetchMarginAccounts()
|
||||
} catch (e) {
|
||||
notify({
|
||||
|
@ -149,7 +156,7 @@ const OpenOrdersTable = () => {
|
|||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{items.map((order, index) => (
|
||||
{items.map( ({order, market}, index) => (
|
||||
<Tr
|
||||
key={`${order.orderId}${order.side}`}
|
||||
className={`border-b border-th-bkg-3
|
||||
|
@ -164,12 +171,11 @@ const OpenOrdersTable = () => {
|
|||
alt=""
|
||||
width="20"
|
||||
height="20"
|
||||
src={`/assets/icons/${order.marketName
|
||||
.split('/')[0]
|
||||
src={`/assets/icons/${market.config.baseSymbol
|
||||
.toLowerCase()}.svg`}
|
||||
className={`mr-2.5`}
|
||||
/>
|
||||
<div>{order.marketName}</div>
|
||||
<div>{market.config.name}</div>
|
||||
</div>
|
||||
</Td>
|
||||
<Td
|
||||
|
@ -199,10 +205,10 @@ const OpenOrdersTable = () => {
|
|||
Modify
|
||||
</Button> */}
|
||||
<Button
|
||||
onClick={() => handleCancelOrder(order)}
|
||||
onClick={() => handleCancelOrder(order, market.account)}
|
||||
className={`ml-3 text-xs pt-0 pb-0 h-8 pl-3 pr-3`}
|
||||
>
|
||||
{cancelId + '' === order?.orderId + '' ? (
|
||||
{cancelId + '' === order.orderId + '' ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<span>Cancel</span>
|
||||
|
|
|
@ -19,7 +19,7 @@ const SECONDS = 1000
|
|||
const useHydrateStore = () => {
|
||||
const setMangoStore = useMangoStore((s) => s.set)
|
||||
const actions = useMangoStore((s) => s.actions)
|
||||
const spotMarkets = useMangoStore((s) => s.selectedMangoGroup.markets)
|
||||
const markets = useMangoStore((s) => s.selectedMangoGroup.markets)
|
||||
const marketConfig = useMangoStore((s) => s.selectedMarket.config)
|
||||
const selectedMarket = useMangoStore((s) => s.selectedMarket.current)
|
||||
|
||||
|
@ -32,24 +32,10 @@ const useHydrateStore = () => {
|
|||
}, 60 * SECONDS)
|
||||
|
||||
useEffect(() => {
|
||||
if (marketConfig.kind === 'spot') {
|
||||
setMangoStore((state) => {
|
||||
state.selectedMarket.current =
|
||||
spotMarkets[marketConfig.publicKey.toString()]
|
||||
markets[marketConfig.publicKey.toString()]
|
||||
})
|
||||
} else {
|
||||
mangoClient
|
||||
.getPerpMarket(
|
||||
marketConfig.publicKey,
|
||||
marketConfig.baseDecimals,
|
||||
marketConfig.quoteDecimals
|
||||
)
|
||||
.then(async (market) => {
|
||||
setMangoStore((state) => {
|
||||
state.selectedMarket.current = market
|
||||
})
|
||||
})
|
||||
}
|
||||
}, [marketConfig])
|
||||
|
||||
// hydrate orderbook with all markets in mango group
|
||||
|
|
|
@ -1,52 +1,64 @@
|
|||
import { Orderbook } from '@project-serum/serum'
|
||||
import { Order as PerpOrder, BookSide, BookSideLayout, getMarketByPublicKey, MarketConfig, PerpMarket, MerpsAccount as MarginAccount, LeafNode, PerpMarketConfig } from '@blockworks-foundation/mango-client'
|
||||
import { Market, OpenOrders, Orderbook } from '@project-serum/serum'
|
||||
import { Order } from '@project-serum/serum/lib/market'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
|
||||
const getOrderBookAccounts = (market, accountInfos) => {
|
||||
const bidData = accountInfos[market._decoded.bids.toString()]?.data
|
||||
const askData = accountInfos[market._decoded.asks.toString()]?.data
|
||||
type OrderInfo = {
|
||||
order: Order | PerpOrder,
|
||||
market: { account: Market | PerpMarket, config: MarketConfig }}
|
||||
|
||||
return {
|
||||
bidOrderBook:
|
||||
market && bidData ? Orderbook.decode(market, Buffer.from(bidData)) : [],
|
||||
askOrderBook:
|
||||
market && askData ? Orderbook.decode(market, Buffer.from(askData)) : [],
|
||||
}
|
||||
function parseSpotOrders(market: Market, config: MarketConfig, marginAccount: MarginAccount, accountInfos) {
|
||||
const openOrders = marginAccount.spotOpenOrdersAccounts[config.marketIndex];
|
||||
const bidData = accountInfos[market['_decoded'].bids.toBase58()]?.data
|
||||
const askData = accountInfos[market['_decoded'].asks.toBase58()]?.data
|
||||
|
||||
const bidOrderBook = market && bidData ? Orderbook.decode(market, bidData) : []
|
||||
const askOrderBook = market && askData ? Orderbook.decode(market, askData) : []
|
||||
|
||||
const openOrdersForMarket = [...bidOrderBook, ...askOrderBook].filter((o) =>
|
||||
o.openOrdersAddress.equals(openOrders.address)
|
||||
)
|
||||
|
||||
return openOrdersForMarket.map<OrderInfo>((order) => ({
|
||||
order,
|
||||
market: { account: market, config: config },
|
||||
}))
|
||||
}
|
||||
|
||||
function parsePerpOpenOrders(market: PerpMarket, config: MarketConfig, marginAccount: MarginAccount, accountInfos) {
|
||||
const bidData = accountInfos[market.bids.toBase58()]?.data
|
||||
const askData = accountInfos[market.asks.toBase58()]?.data
|
||||
|
||||
const bidOrderBook = market && bidData ? new BookSide(market.bids, market, BookSideLayout.decode(bidData)) : []
|
||||
const askOrderBook = market && askData ? new BookSide(market.asks, market, BookSideLayout.decode(askData)) : []
|
||||
|
||||
const openOrdersForMarket = [...bidOrderBook, ...askOrderBook].filter((o) =>
|
||||
o.owner.equals(marginAccount.publicKey)
|
||||
)
|
||||
|
||||
return openOrdersForMarket.map<OrderInfo>((order) => ({
|
||||
order,
|
||||
market: { account: market, config: config },
|
||||
}));
|
||||
}
|
||||
|
||||
export function useOpenOrders() {
|
||||
const markets = useMangoStore((s) => s.selectedMangoGroup.markets)
|
||||
const marginAccount = useMangoStore((s) => s.selectedMarginAccount.current)
|
||||
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const mangoGroupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
|
||||
const groupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
|
||||
const accountInfos = useMangoStore((s) => s.accountInfos)
|
||||
|
||||
if (!mangoGroup || !marginAccount || !accountInfos) return null
|
||||
|
||||
const openOrders = Object.entries(markets).map(([address, market]) => {
|
||||
const marketIndex = mangoGroup.getSpotMarketIndex(new PublicKey(address))
|
||||
const openOrdersAccount = marginAccount.spotOpenOrdersAccounts[marketIndex]
|
||||
|
||||
const marketName = mangoGroupConfig.spotMarkets.find(
|
||||
(mkt) => mkt.publicKey.toString() === address
|
||||
).name
|
||||
|
||||
if (!openOrdersAccount) return []
|
||||
|
||||
const { bidOrderBook, askOrderBook } = getOrderBookAccounts(
|
||||
market,
|
||||
accountInfos
|
||||
)
|
||||
|
||||
const openOrdersForMarket = [...bidOrderBook, ...askOrderBook].filter((o) =>
|
||||
o.openOrdersAddress.equals(openOrdersAccount.address)
|
||||
)
|
||||
|
||||
return openOrdersForMarket.map((order) => ({
|
||||
...order,
|
||||
marketName,
|
||||
market,
|
||||
}))
|
||||
const openOrders = Object.entries(markets).map(([address, market]) => {
|
||||
const marketConfig = getMarketByPublicKey(groupConfig, address)
|
||||
if (market instanceof Market) {
|
||||
return parseSpotOrders(market, marketConfig, marginAccount, accountInfos);
|
||||
} else if (market instanceof PerpMarket) {
|
||||
return parsePerpOpenOrders(market, marketConfig, marginAccount, accountInfos);
|
||||
}
|
||||
})
|
||||
|
||||
return openOrders.flat()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useMemo, useState } from 'react'
|
||||
|
||||
export const useSortableData = (items, config = null) => {
|
||||
export function useSortableData<T>(items: T[], config = null): { items: T[], requestSort: any, sortConfig: any } {
|
||||
const [sortConfig, setSortConfig] = useState(config)
|
||||
|
||||
const sortedItems = useMemo(() => {
|
||||
|
|
|
@ -18,7 +18,11 @@ import {
|
|||
nativeToUi,
|
||||
MerpsCache,
|
||||
PerpMarket,
|
||||
getAllMarkets,
|
||||
getMultipleAccounts,
|
||||
PerpMarketConfig,
|
||||
SpotMarketConfig,
|
||||
PerpMarketLayout,
|
||||
} from '@blockworks-foundation/mango-client'
|
||||
// import { SRM_DECIMALS } from '@project-serum/serum/lib/token-instructions'
|
||||
import {
|
||||
|
@ -31,9 +35,11 @@ import {
|
|||
import { EndpointInfo, WalletAdapter } from '../@types/types'
|
||||
import { getWalletTokenInfo } from '../utils/tokens'
|
||||
import {
|
||||
chunks,
|
||||
decodeAndLoadMarkets,
|
||||
getOrderBookAccountInfos,
|
||||
isDefined,
|
||||
zipDict,
|
||||
} from '../utils'
|
||||
import { notify } from '../utils/notifications'
|
||||
import useAllMarkets from '../hooks/useAllMarkets'
|
||||
|
@ -139,10 +145,10 @@ interface MangoStore extends State {
|
|||
name: string
|
||||
current: MangoGroup | null
|
||||
markets: {
|
||||
[address: string]: Market
|
||||
[address: string]: Market | PerpMarket
|
||||
}
|
||||
rootBanks: any[]
|
||||
cache: MerpsCache | null
|
||||
cache: MerpsCache | null
|
||||
}
|
||||
marginAccounts: MarginAccount[]
|
||||
selectedMarginAccount: {
|
||||
|
@ -316,34 +322,42 @@ const useMangoStore = create<MangoStore>((set, get) => ({
|
|||
return mangoClient
|
||||
.getMerpsGroup(mangoGroupPk)
|
||||
.then(async (mangoGroup) => {
|
||||
// TODO also perps
|
||||
const rootBanks = await mangoGroup.loadRootBanks(DEFAULT_CONNECTION)
|
||||
const merpsCache = await mangoGroup.loadCache(DEFAULT_CONNECTION)
|
||||
|
||||
const spotMarketAccountInfos = await getMultipleAccounts(
|
||||
DEFAULT_CONNECTION,
|
||||
mangoGroupConfig.spotMarkets.map((mkt) => mkt.publicKey)
|
||||
)
|
||||
const spotOrderBookAccountInfos = await getOrderBookAccountInfos(
|
||||
mangoGroup.dexProgramId,
|
||||
spotMarketAccountInfos.map(({ accountInfo }) => accountInfo)
|
||||
)
|
||||
const spotMarkets = await decodeAndLoadMarkets(
|
||||
mangoGroupConfig,
|
||||
spotMarketAccountInfos
|
||||
)
|
||||
const allMarketConfigs = getAllMarkets(mangoGroupConfig);
|
||||
const allMarketPks = allMarketConfigs.map(m => m.publicKey);
|
||||
const allMarketAccountInfos = await getMultipleAccounts(DEFAULT_CONNECTION, allMarketPks);
|
||||
const allMarketAccounts = allMarketConfigs.map((config, i) => {
|
||||
if (config.kind == 'spot') {
|
||||
const decoded = Market.getLayout(programId).decode(allMarketAccountInfos[i].accountInfo.data);
|
||||
return new Market(decoded, config.baseDecimals, config.quoteDecimals, undefined, mangoGroupConfig.serumProgramId);
|
||||
}
|
||||
if (config.kind == 'perp') {
|
||||
const decoded = PerpMarketLayout.decode(allMarketAccountInfos[i].accountInfo.data);
|
||||
return new PerpMarket(config.publicKey, config.baseDecimals, config.quoteDecimals, decoded);
|
||||
}
|
||||
})
|
||||
|
||||
const allBidsAndAsksPks = allMarketConfigs.map(m => [m.bidsKey, m.asksKey]).flat()
|
||||
const allBidsAndAsksAccountInfos = await getMultipleAccounts(DEFAULT_CONNECTION, allBidsAndAsksPks);
|
||||
|
||||
const allMarkets = zipDict(allMarketPks.map(pk => pk.toBase58()), allMarketAccounts);
|
||||
console.log('all', allMarkets);
|
||||
|
||||
set((state) => {
|
||||
state.selectedMangoGroup.current = mangoGroup
|
||||
state.selectedMangoGroup.rootBanks = rootBanks
|
||||
state.selectedMangoGroup.cache = merpsCache
|
||||
state.selectedMangoGroup.markets = spotMarkets
|
||||
state.selectedMarket.current =
|
||||
spotMarkets[selectedMarketConfig.publicKey.toString()]
|
||||
state.selectedMangoGroup.markets = allMarkets
|
||||
state.selectedMarket.current = allMarkets[selectedMarketConfig.publicKey.toBase58()]
|
||||
|
||||
spotMarketAccountInfos
|
||||
.concat(spotOrderBookAccountInfos)
|
||||
allMarketAccountInfos
|
||||
.concat(allBidsAndAsksAccountInfos)
|
||||
.forEach(({ publicKey, accountInfo }) => {
|
||||
state.accountInfos[publicKey.toString()] = accountInfo
|
||||
console.log(publicKey.toBase58(), accountInfo)
|
||||
state.accountInfos[publicKey.toBase58()] = accountInfo
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -208,6 +208,20 @@ export const capitalize = (s) => {
|
|||
return s.charAt(0).toUpperCase() + s.slice(1)
|
||||
}
|
||||
|
||||
export function* chunks(arr, n) {
|
||||
for (let i = 0; i < arr.length; i += n) {
|
||||
yield arr.slice(i, i + n)
|
||||
}
|
||||
}
|
||||
|
||||
export function zipDict<K, V>(keys: K[], values: V[]): Record<K, V> {
|
||||
let result: Record<K, V> = {}
|
||||
keys.forEach((key, index) => {
|
||||
result[key] = values[index]
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
export const copyToClipboard = (copyThis) => {
|
||||
const el = document.createElement('textarea')
|
||||
el.value = copyThis.toString()
|
||||
|
|
|
@ -988,7 +988,7 @@
|
|||
|
||||
"@blockworks-foundation/mango-client@git+ssh://git@github.com/blockworks-foundation/merps-ts#main":
|
||||
version "0.0.0"
|
||||
resolved "git+ssh://git@github.com/blockworks-foundation/merps-ts#67e15d85ee1120a049358c12a46929bdc9ae31ce"
|
||||
resolved "git+ssh://git@github.com/blockworks-foundation/merps-ts#1f2e298d58badd27069f89e2355550ff5d036ed3"
|
||||
dependencies:
|
||||
"@project-serum/serum" "^0.13.38"
|
||||
"@project-serum/sol-wallet-adapter" "^0.2.0"
|
||||
|
|
Loading…
Reference in New Issue