146 lines
3.9 KiB
TypeScript
146 lines
3.9 KiB
TypeScript
import mangoStore from '@store/mangoStore'
|
|
import { useMemo } from 'react'
|
|
import useMangoAccount from './useMangoAccount'
|
|
import {
|
|
PerpOo,
|
|
PerpPosition,
|
|
Serum3Orders,
|
|
TokenPosition,
|
|
} from '@blockworks-foundation/mango-v4'
|
|
import { MAX_ACCOUNTS } from 'utils/constants'
|
|
import { OpenOrders } from '@project-serum/serum'
|
|
import { BN } from '@coral-xyz/anchor'
|
|
|
|
export const getAvaialableAccountsColor = (used: number, total: number) => {
|
|
const remaining = total - used
|
|
return remaining >= 4
|
|
? 'text-th-up'
|
|
: remaining >= 2
|
|
? 'text-th-warning'
|
|
: 'text-th-down'
|
|
}
|
|
|
|
const isAccountSlotFull = (slots: number, max: string) => {
|
|
const numberMax = Number(max)
|
|
return slots >= numberMax
|
|
}
|
|
|
|
const getIsAccountSizeFull = () => {
|
|
const mangoAccount = mangoStore.getState().mangoAccount.current
|
|
if (!mangoAccount) return true
|
|
return (
|
|
isAccountSlotFull(
|
|
mangoAccount.tokens.length,
|
|
MAX_ACCOUNTS.tokenAccounts!,
|
|
) &&
|
|
isAccountSlotFull(
|
|
mangoAccount.serum3.length,
|
|
MAX_ACCOUNTS.spotOpenOrders!,
|
|
) &&
|
|
isAccountSlotFull(mangoAccount.perps.length, MAX_ACCOUNTS.perpAccounts!) &&
|
|
isAccountSlotFull(
|
|
mangoAccount.perpOpenOrders.length,
|
|
MAX_ACCOUNTS.perpOpenOrders!,
|
|
)
|
|
)
|
|
}
|
|
|
|
export default function useMangoAccountAccounts() {
|
|
const { mangoAccount } = useMangoAccount()
|
|
|
|
const [
|
|
usedTokens,
|
|
usedSerum3,
|
|
usedPerps,
|
|
usedPerpOo,
|
|
emptySerum3,
|
|
emptyPerps,
|
|
usedTcs,
|
|
] = useMemo(() => {
|
|
if (!mangoAccount) return [[], [], [], [], [], [], []]
|
|
|
|
const { tokens, serum3, perps, perpOpenOrders, tokenConditionalSwaps } =
|
|
mangoAccount
|
|
const usedTokens: TokenPosition[] = tokens.filter(
|
|
(t) => t.tokenIndex !== 65535,
|
|
)
|
|
const usedSerum3: Serum3Orders[] = serum3.filter(
|
|
(s) => s.marketIndex !== 65535,
|
|
)
|
|
const usedPerps: PerpPosition[] = perps.filter(
|
|
(p) => p.marketIndex !== 65535,
|
|
)
|
|
const usedPerpOo: PerpOo[] = perpOpenOrders.filter(
|
|
(p) => p.orderMarket !== 65535,
|
|
)
|
|
const usedTcs = tokenConditionalSwaps.filter((tcs) => tcs.hasData)
|
|
|
|
const emptyPerps = usedPerps.filter(
|
|
(p) =>
|
|
p.asksBaseLots.isZero() &&
|
|
p.bidsBaseLots.isZero() &&
|
|
p.takerBaseLots.isZero &&
|
|
p.takerQuoteLots.isZero() &&
|
|
p.basePositionLots.isZero() &&
|
|
p.quotePositionNative.isZero(),
|
|
)
|
|
|
|
const usedOpenOrders = usedSerum3
|
|
.map((s) => mangoAccount.serum3OosMapByMarketIndex.get(s.marketIndex))
|
|
.filter((o) => o !== undefined) as OpenOrders[]
|
|
const maxFreeSlotBits = new BN(2).pow(new BN(128)).sub(new BN(1)) // 2^128 - 1
|
|
const emptySerum3Keys = usedOpenOrders
|
|
.filter(
|
|
(o) =>
|
|
o.baseTokenTotal.isZero() &&
|
|
o.quoteTokenTotal.isZero() &&
|
|
o.freeSlotBits.eq(maxFreeSlotBits),
|
|
)
|
|
.map((f) => f.address)
|
|
const emptySerum3 = usedSerum3.filter((s) =>
|
|
emptySerum3Keys.includes(s.openOrders),
|
|
)
|
|
|
|
return [
|
|
usedTokens,
|
|
usedSerum3,
|
|
usedPerps,
|
|
usedPerpOo,
|
|
emptySerum3,
|
|
emptyPerps,
|
|
usedTcs,
|
|
]
|
|
}, [mangoAccount])
|
|
|
|
const [totalTokens, totalSerum3, totalPerps, totalPerpOpenOrders] =
|
|
useMemo(() => {
|
|
if (!mangoAccount) return [[], [], [], []]
|
|
const { tokens, serum3, perps, perpOpenOrders } = mangoAccount
|
|
const totalTokens = tokens
|
|
const totalSerum3 = serum3
|
|
const totalPerps = perps
|
|
const totalPerpOpenOrders = perpOpenOrders
|
|
return [totalTokens, totalSerum3, totalPerps, totalPerpOpenOrders]
|
|
}, [mangoAccount])
|
|
|
|
const isAccountFull = useMemo(() => {
|
|
if (!mangoAccount) return true
|
|
return getIsAccountSizeFull()
|
|
}, [mangoAccount])
|
|
|
|
return {
|
|
usedTokens,
|
|
usedSerum3,
|
|
usedPerps,
|
|
usedPerpOo,
|
|
usedTcs,
|
|
emptySerum3,
|
|
emptyPerps,
|
|
totalTokens,
|
|
totalSerum3,
|
|
totalPerps,
|
|
totalPerpOpenOrders,
|
|
isAccountFull,
|
|
}
|
|
}
|