Merge branch 'main' into edit-orders

This commit is contained in:
Adrian Brzeziński 2022-12-15 02:08:17 +01:00
commit 0ebad8d9a3
14 changed files with 186 additions and 122 deletions

View File

@ -2,7 +2,6 @@ import { Bank, Serum3Market } from '@blockworks-foundation/mango-v4'
import useJupiterMints from 'hooks/useJupiterMints' import useJupiterMints from 'hooks/useJupiterMints'
import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid' import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid'
import mangoStore from '@store/mangoStore' import mangoStore from '@store/mangoStore'
import Decimal from 'decimal.js'
import useMangoAccount from 'hooks/useMangoAccount' import useMangoAccount from 'hooks/useMangoAccount'
import { useViewport } from 'hooks/useViewport' import { useViewport } from 'hooks/useViewport'
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
@ -17,7 +16,7 @@ import {
trimDecimals, trimDecimals,
} from 'utils/numbers' } from 'utils/numbers'
import { breakpoints } from 'utils/theme' import { breakpoints } from 'utils/theme'
import { calculateMarketPrice } from 'utils/tradeForm' import { calculateLimitPriceForMarketOrder } from 'utils/tradeForm'
import { LinkButton } from './Button' import { LinkButton } from './Button'
import { Table, Td, Th, TrBody, TrHead } from './TableElements' import { Table, Td, Th, TrBody, TrHead } from './TableElements'
import useSelectedMarket from 'hooks/useSelectedMarket' import useSelectedMarket from 'hooks/useSelectedMarket'
@ -218,9 +217,9 @@ const Balance = ({ bank }: { bank: Bank }) => {
(balance > 0 && type === 'quote') || (balance < 0 && type === 'base') (balance > 0 && type === 'quote') || (balance < 0 && type === 'base')
? 'buy' ? 'buy'
: 'sell' : 'sell'
price = calculateMarketPrice(orderbook, balance, side) price = calculateLimitPriceForMarketOrder(orderbook, balance, side)
} else { } else {
price = new Decimal(tradeForm.price).toNumber() price = Number(tradeForm.price)
} }
let minOrderDecimals: number let minOrderDecimals: number

View File

@ -61,6 +61,16 @@ export const getTokenInMax = (
inputBank.mintDecimals inputBank.mintDecimals
) )
console.log(
'getMaxSourceUiForTokenSwap',
mangoAccount.getMaxSourceUiForTokenSwap(
group,
inputBank.mint,
outputBank.mint,
inputBank.uiPrice / outputBank.uiPrice
)
)
const inputBankVaultBalance = floorToDecimal( const inputBankVaultBalance = floorToDecimal(
group.getTokenVaultBalanceByMintUi(inputBank.mint), group.getTokenVaultBalanceByMintUi(inputBank.mint),
inputBank.mintDecimals inputBank.mintDecimals

View File

@ -22,7 +22,7 @@ import NumberFormat, {
} from 'react-number-format' } from 'react-number-format'
import { notify } from 'utils/notifications' import { notify } from 'utils/notifications'
import SpotSlider from './SpotSlider' import SpotSlider from './SpotSlider'
import { calculateMarketPrice } from 'utils/tradeForm' import { calculateLimitPriceForMarketOrder } from 'utils/tradeForm'
import Image from 'next/legacy/image' import Image from 'next/legacy/image'
import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid' import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid'
import Loading from '@components/shared/Loading' import Loading from '@components/shared/Loading'
@ -45,12 +45,13 @@ const TABS: [string, number][] = [
['Market', 0], ['Market', 0],
] ]
const set = mangoStore.getState().set
const AdvancedTradeForm = () => { const AdvancedTradeForm = () => {
const { t } = useTranslation(['common', 'trade']) const { t } = useTranslation(['common', 'trade'])
const set = mangoStore.getState().set
const tradeForm = mangoStore((s) => s.tradeForm) const tradeForm = mangoStore((s) => s.tradeForm)
const { mangoTokens } = useJupiterMints() const { mangoTokens } = useJupiterMints()
const { selectedMarket, price: marketPrice } = useSelectedMarket() const { selectedMarket, price: oraclePrice } = useSelectedMarket()
const [useMargin, setUseMargin] = useState(true) const [useMargin, setUseMargin] = useState(true)
const [placingOrder, setPlacingOrder] = useState(false) const [placingOrder, setPlacingOrder] = useState(false)
const [tradeFormSizeUi] = useLocalStorageState(SIZE_INPUT_UI_KEY, 'Slider') const [tradeFormSizeUi] = useLocalStorageState(SIZE_INPUT_UI_KEY, 'Slider')
@ -93,14 +94,11 @@ const AdvancedTradeForm = () => {
return '' return ''
}, [quoteSymbol, mangoTokens]) }, [quoteSymbol, mangoTokens])
const setTradeType = useCallback( const setTradeType = useCallback((tradeType: 'Limit' | 'Market') => {
(tradeType: 'Limit' | 'Market') => { set((s) => {
set((s) => { s.tradeForm.tradeType = tradeType
s.tradeForm.tradeType = tradeType })
}) }, [])
},
[set]
)
const handlePriceChange = useCallback( const handlePriceChange = useCallback(
(e: NumberFormatValues, info: SourceInfo) => { (e: NumberFormatValues, info: SourceInfo) => {
@ -114,7 +112,7 @@ const AdvancedTradeForm = () => {
} }
}) })
}, },
[set] []
) )
const handleBaseSizeChange = useCallback( const handleBaseSizeChange = useCallback(
@ -123,8 +121,8 @@ const AdvancedTradeForm = () => {
set((s) => { set((s) => {
const price = const price =
s.tradeForm.tradeType === 'Market' s.tradeForm.tradeType === 'Market'
? marketPrice ? oraclePrice
: parseFloat(s.tradeForm.price) : Number(s.tradeForm.price)
s.tradeForm.baseSize = e.value s.tradeForm.baseSize = e.value
if (price && e.value !== '' && !Number.isNaN(Number(e.value))) { if (price && e.value !== '' && !Number.isNaN(Number(e.value))) {
@ -134,7 +132,7 @@ const AdvancedTradeForm = () => {
} }
}) })
}, },
[set, marketPrice] [oraclePrice]
) )
const handleQuoteSizeChange = useCallback( const handleQuoteSizeChange = useCallback(
@ -143,8 +141,8 @@ const AdvancedTradeForm = () => {
set((s) => { set((s) => {
const price = const price =
s.tradeForm.tradeType === 'Market' s.tradeForm.tradeType === 'Market'
? marketPrice ? oraclePrice
: parseFloat(s.tradeForm.price) : Number(s.tradeForm.price)
s.tradeForm.quoteSize = e.value s.tradeForm.quoteSize = e.value
if (price && e.value !== '' && !Number.isNaN(Number(e.value))) { if (price && e.value !== '' && !Number.isNaN(Number(e.value))) {
@ -154,47 +152,55 @@ const AdvancedTradeForm = () => {
} }
}) })
}, },
[set, marketPrice] [oraclePrice]
) )
const handlePostOnlyChange = useCallback( const handlePostOnlyChange = useCallback((postOnly: boolean) => {
(postOnly: boolean) => { set((s) => {
s.tradeForm.postOnly = postOnly
if (s.tradeForm.ioc === true) {
s.tradeForm.ioc = !postOnly
}
})
}, [])
const handleIocChange = useCallback((ioc: boolean) => {
set((s) => {
s.tradeForm.ioc = ioc
if (s.tradeForm.postOnly === true) {
s.tradeForm.postOnly = !ioc
}
})
}, [])
const handleSetSide = useCallback((side: 'buy' | 'sell') => {
set((s) => {
s.tradeForm.side = side
})
}, [])
/*
* Updates the limit price on page load
*/
useEffect(() => {
if (tradeForm.price === undefined) {
const group = mangoStore.getState().group
if (!group || !oraclePrice) return
set((s) => { set((s) => {
s.tradeForm.postOnly = postOnly s.tradeForm.price = oraclePrice.toString()
if (s.tradeForm.ioc === true) {
s.tradeForm.ioc = !postOnly
}
}) })
}, }
[set] }, [oraclePrice, tradeForm.price])
)
const handleIocChange = useCallback(
(ioc: boolean) => {
set((s) => {
s.tradeForm.ioc = ioc
if (s.tradeForm.postOnly === true) {
s.tradeForm.postOnly = !ioc
}
})
},
[set]
)
const handleSetSide = useCallback(
(side: 'buy' | 'sell') => {
set((s) => {
s.tradeForm.side = side
})
},
[set]
)
/*
* Updates the price and the quote size when a Market order is selected
*/
useEffect(() => { useEffect(() => {
const group = mangoStore.getState().group const group = mangoStore.getState().group
if ( if (
tradeForm.tradeType === 'Market' && tradeForm.tradeType === 'Market' &&
marketPrice && oraclePrice &&
selectedMarket && selectedMarket &&
group group
) { ) {
@ -209,20 +215,18 @@ const AdvancedTradeForm = () => {
} }
if (!isNaN(parseFloat(tradeForm.baseSize))) { if (!isNaN(parseFloat(tradeForm.baseSize))) {
const baseSize = new Decimal(tradeForm.baseSize)?.toNumber() const baseSize = new Decimal(tradeForm.baseSize)?.toNumber()
const orderbook = mangoStore.getState().selectedMarket.orderbook const quoteSize = baseSize * oraclePrice
const price = calculateMarketPrice(orderbook, baseSize, tradeForm.side)
const quoteSize = baseSize * price
set((s) => { set((s) => {
s.tradeForm.price = price.toFixed(getDecimalCount(tickSize)) s.tradeForm.price = oraclePrice.toFixed(getDecimalCount(tickSize))
s.tradeForm.quoteSize = quoteSize.toFixed(getDecimalCount(tickSize)) s.tradeForm.quoteSize = quoteSize.toFixed(getDecimalCount(tickSize))
}) })
} else { } else {
set((s) => { set((s) => {
s.tradeForm.price = marketPrice.toFixed(getDecimalCount(tickSize)) s.tradeForm.price = oraclePrice.toFixed(getDecimalCount(tickSize))
}) })
} }
} }
}, [marketPrice, selectedMarket, tradeForm]) }, [oraclePrice, selectedMarket, tradeForm])
const handlePlaceOrder = useCallback(async () => { const handlePlaceOrder = useCallback(async () => {
const client = mangoStore.getState().client const client = mangoStore.getState().client
@ -235,11 +239,15 @@ const AdvancedTradeForm = () => {
if (!group || !mangoAccount) return if (!group || !mangoAccount) return
setPlacingOrder(true) setPlacingOrder(true)
try { try {
const baseSize = new Decimal(tradeForm.baseSize).toNumber() const baseSize = Number(tradeForm.baseSize)
let price = new Decimal(tradeForm.price).toNumber() let price = Number(tradeForm.price)
if (tradeForm.tradeType === 'Market') { if (tradeForm.tradeType === 'Market') {
const orderbook = mangoStore.getState().selectedMarket.orderbook const orderbook = mangoStore.getState().selectedMarket.orderbook
price = calculateMarketPrice(orderbook, baseSize, tradeForm.side) price = calculateLimitPriceForMarketOrder(
orderbook,
baseSize,
tradeForm.side
)
} }
if (selectedMarket instanceof Serum3Market) { if (selectedMarket instanceof Serum3Market) {
@ -260,7 +268,6 @@ const AdvancedTradeForm = () => {
Date.now(), Date.now(),
10 10
) )
actions.reloadMangoAccount()
actions.fetchOpenOrders() actions.fetchOpenOrders()
notify({ notify({
type: 'success', type: 'success',
@ -289,7 +296,6 @@ const AdvancedTradeForm = () => {
undefined, undefined,
undefined undefined
) )
actions.reloadMangoAccount()
actions.fetchOpenOrders() actions.fetchOpenOrders()
notify({ notify({
type: 'success', type: 'success',
@ -308,7 +314,7 @@ const AdvancedTradeForm = () => {
} finally { } finally {
setPlacingOrder(false) setPlacingOrder(false)
} }
}, [t]) }, [])
const maintProjectedHealth = useMemo(() => { const maintProjectedHealth = useMemo(() => {
const group = mangoStore.getState().group const group = mangoStore.getState().group
@ -344,13 +350,13 @@ const AdvancedTradeForm = () => {
group, group,
selectedMarket.perpMarketIndex, selectedMarket.perpMarketIndex,
parseFloat(tradeForm.baseSize), parseFloat(tradeForm.baseSize),
parseFloat(tradeForm.price) Number(tradeForm.price)
) )
: mangoAccount.simHealthRatioWithPerpBidUiChanges( : mangoAccount.simHealthRatioWithPerpBidUiChanges(
group, group,
selectedMarket.perpMarketIndex, selectedMarket.perpMarketIndex,
parseFloat(tradeForm.baseSize), parseFloat(tradeForm.baseSize),
parseFloat(tradeForm.price) Number(tradeForm.price)
) )
} }
} catch (e) { } catch (e) {

View File

@ -23,13 +23,13 @@ const PerpButtonGroup = () => {
return mangoAccount.getMaxQuoteForPerpBidUi( return mangoAccount.getMaxQuoteForPerpBidUi(
group, group,
selectedMarket.perpMarketIndex, selectedMarket.perpMarketIndex,
parseFloat(tradeFormPrice) Number(tradeFormPrice)
) )
} else { } else {
return mangoAccount.getMaxBaseForPerpAskUi( return mangoAccount.getMaxBaseForPerpAskUi(
group, group,
selectedMarket.perpMarketIndex, selectedMarket.perpMarketIndex,
parseFloat(tradeFormPrice) Number(tradeFormPrice)
) )
} }
} catch (e) { } catch (e) {
@ -53,9 +53,7 @@ const PerpButtonGroup = () => {
s.tradeForm.quoteSize = size.toString() s.tradeForm.quoteSize = size.toString()
if (Number(s.tradeForm.price)) { if (Number(s.tradeForm.price)) {
s.tradeForm.baseSize = ( s.tradeForm.baseSize = (size / Number(s.tradeForm.price)).toString()
size / parseFloat(s.tradeForm.price)
).toString()
} else { } else {
s.tradeForm.baseSize = '' s.tradeForm.baseSize = ''
} }
@ -64,7 +62,7 @@ const PerpButtonGroup = () => {
if (Number(s.tradeForm.price)) { if (Number(s.tradeForm.price)) {
s.tradeForm.quoteSize = ( s.tradeForm.quoteSize = (
size * parseFloat(s.tradeForm.price) size * Number(s.tradeForm.price)
).toString() ).toString()
} }
} }

View File

@ -4,7 +4,6 @@ import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements'
import { LinkIcon, NoSymbolIcon } from '@heroicons/react/20/solid' import { LinkIcon, NoSymbolIcon } from '@heroicons/react/20/solid'
import { useWallet } from '@solana/wallet-adapter-react' import { useWallet } from '@solana/wallet-adapter-react'
import mangoStore from '@store/mangoStore' import mangoStore from '@store/mangoStore'
import Decimal from 'decimal.js'
import useMangoGroup from 'hooks/useMangoGroup' import useMangoGroup from 'hooks/useMangoGroup'
import useSelectedMarket from 'hooks/useSelectedMarket' import useSelectedMarket from 'hooks/useSelectedMarket'
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
@ -14,7 +13,7 @@ import {
numberFormat, numberFormat,
trimDecimals, trimDecimals,
} from 'utils/numbers' } from 'utils/numbers'
import { calculateMarketPrice } from 'utils/tradeForm' import { calculateLimitPriceForMarketOrder } from 'utils/tradeForm'
import PerpSideBadge from './PerpSideBadge' import PerpSideBadge from './PerpSideBadge'
import TableMarketName from './TableMarketName' import TableMarketName from './TableMarketName'
@ -29,10 +28,14 @@ const PerpPositions = () => {
const tradeForm = mangoStore.getState().tradeForm const tradeForm = mangoStore.getState().tradeForm
const set = mangoStore.getState().set const set = mangoStore.getState().set
let price = new Decimal(tradeForm.price).toNumber() let price = Number(tradeForm.price)
if (tradeForm.tradeType === 'Market') { if (tradeForm.tradeType === 'Market') {
const orderbook = mangoStore.getState().selectedMarket.orderbook const orderbook = mangoStore.getState().selectedMarket.orderbook
price = calculateMarketPrice(orderbook, positionSize, tradeForm.side) price = calculateLimitPriceForMarketOrder(
orderbook,
positionSize,
tradeForm.side
)
} }
const newSide = positionSize > 0 ? 'sell' : 'buy' const newSide = positionSize > 0 ? 'sell' : 'buy'

View File

@ -29,13 +29,13 @@ const PerpSlider = () => {
return mangoAccount.getMaxQuoteForPerpBidUi( return mangoAccount.getMaxQuoteForPerpBidUi(
group, group,
selectedMarket.perpMarketIndex, selectedMarket.perpMarketIndex,
parseFloat(tradeForm.price) Number(tradeForm.price)
) )
} else { } else {
return mangoAccount.getMaxBaseForPerpAskUi( return mangoAccount.getMaxBaseForPerpAskUi(
group, group,
selectedMarket.perpMarketIndex, selectedMarket.perpMarketIndex,
parseFloat(tradeForm.price) Number(tradeForm.price)
) )
} }
} catch (e) { } catch (e) {
@ -56,7 +56,7 @@ const PerpSlider = () => {
const price = const price =
s.tradeForm.tradeType === 'Market' s.tradeForm.tradeType === 'Market'
? marketPrice ? marketPrice
: parseFloat(s.tradeForm.price) : Number(s.tradeForm.price)
if (s.tradeForm.side === 'buy') { if (s.tradeForm.side === 'buy') {
s.tradeForm.quoteSize = val s.tradeForm.quoteSize = val

View File

@ -50,9 +50,7 @@ const SpotButtonGroup = () => {
s.tradeForm.quoteSize = size.toString() s.tradeForm.quoteSize = size.toString()
if (Number(s.tradeForm.price)) { if (Number(s.tradeForm.price)) {
s.tradeForm.baseSize = ( s.tradeForm.baseSize = (size / Number(s.tradeForm.price)).toString()
size / parseFloat(s.tradeForm.price)
).toString()
} else { } else {
s.tradeForm.baseSize = '' s.tradeForm.baseSize = ''
} }
@ -61,7 +59,7 @@ const SpotButtonGroup = () => {
if (Number(s.tradeForm.price)) { if (Number(s.tradeForm.price)) {
s.tradeForm.quoteSize = ( s.tradeForm.quoteSize = (
size * parseFloat(s.tradeForm.price) size * Number(s.tradeForm.price)
).toString() ).toString()
} }
} }

View File

@ -47,7 +47,7 @@ const SpotSlider = () => {
const price = const price =
s.tradeForm.tradeType === 'Market' s.tradeForm.tradeType === 'Market'
? marketPrice ? marketPrice
: parseFloat(s.tradeForm.price) : Number(s.tradeForm.price)
if (s.tradeForm.side === 'buy') { if (s.tradeForm.side === 'buy') {
s.tradeForm.quoteSize = val s.tradeForm.quoteSize = val

View File

@ -45,7 +45,6 @@ const UnsettledTrades = ({
new PublicKey(mktAddress) new PublicKey(mktAddress)
) )
actions.fetchOpenOrders() actions.fetchOpenOrders()
actions.reloadMangoAccount()
notify({ notify({
type: 'success', type: 'success',
title: 'Successfully settled funds', title: 'Successfully settled funds',

View File

@ -4,7 +4,10 @@ import type { NextPage } from 'next'
import { ReactNode } from 'react' import { ReactNode } from 'react'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import useMangoAccount from 'hooks/useMangoAccount' import useMangoAccount from 'hooks/useMangoAccount'
import { toUiDecimalsForQuote, HealthType } from '@blockworks-foundation/mango-v4'; import {
toUiDecimalsForQuote,
HealthType,
} from '@blockworks-foundation/mango-v4'
export async function getStaticProps({ locale }: { locale: string }) { export async function getStaticProps({ locale }: { locale: string }) {
return { return {
@ -56,19 +59,27 @@ const Dashboard: NextPage = () => {
/> />
<KeyValuePair <KeyValuePair
label="Init Health" label="Init Health"
value={`$${toUiDecimalsForQuote(mangoAccount.getHealth(group, HealthType.init)).toFixed(4)}`} value={`$${toUiDecimalsForQuote(
mangoAccount.getHealth(group, HealthType.init)
).toFixed(4)}`}
/> />
<KeyValuePair <KeyValuePair
label="Maint Health" label="Maint Health"
value={`$${toUiDecimalsForQuote(mangoAccount.getHealth(group, HealthType.maint)).toFixed(4)}`} value={`$${toUiDecimalsForQuote(
mangoAccount.getHealth(group, HealthType.maint)
).toFixed(4)}`}
/> />
<KeyValuePair <KeyValuePair
label="Perp Settle Health" label="Perp Settle Health"
value={`$${toUiDecimalsForQuote(mangoAccount.getPerpSettleHealth(group)).toFixed(4)}`} value={`$${toUiDecimalsForQuote(
mangoAccount.getPerpSettleHealth(group)
).toFixed(4)}`}
/> />
<KeyValuePair <KeyValuePair
label="Net Deposits" label="Net Deposits"
value={`$${toUiDecimalsForQuote(mangoAccount.netDeposits).toFixed(4)}`} value={`$${toUiDecimalsForQuote(
mangoAccount.netDeposits
).toFixed(4)}`}
/> />
<KeyValuePair <KeyValuePair
label="Perp Spot Transfers" label="Perp Spot Transfers"
@ -154,7 +165,9 @@ const Dashboard: NextPage = () => {
/> />
<KeyValuePair <KeyValuePair
label="Quote Position UI" label="Quote Position UI"
value={`$${toUiDecimalsForQuote(perp.quotePositionNative).toFixed(4)}`} value={`$${toUiDecimalsForQuote(
perp.quotePositionNative
).toFixed(4)}`}
/> />
<KeyValuePair <KeyValuePair
label="Quote Running Native" label="Quote Running Native"

View File

@ -1,5 +1,10 @@
import {
Group,
PerpMarket,
Serum3Market,
} from '@blockworks-foundation/mango-v4'
import TradeAdvancedPage from '@components/trade/TradeAdvancedPage' import TradeAdvancedPage from '@components/trade/TradeAdvancedPage'
import mangoStore from '@store/mangoStore' import mangoStore, { DEFAULT_TRADE_FORM } from '@store/mangoStore'
// import mangoStore from '@store/mangoStore' // import mangoStore from '@store/mangoStore'
import type { NextPage } from 'next' import type { NextPage } from 'next'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
@ -20,6 +25,23 @@ export async function getStaticProps({ locale }: { locale: string }) {
} }
} }
const getOraclePriceForMarket = (
group: Group,
mkt: Serum3Market | PerpMarket
): number => {
let price: number
if (mkt instanceof Serum3Market) {
const baseBank = group.getFirstBankByTokenIndex(mkt.baseTokenIndex)
price = baseBank.uiPrice
} else if (mkt) {
price = mkt._uiPrice
} else {
price = 0
}
return price
}
const Trade: NextPage = () => { const Trade: NextPage = () => {
const router = useRouter() const router = useRouter()
const { name: marketName } = router.query const { name: marketName } = router.query
@ -34,10 +56,15 @@ const Trade: NextPage = () => {
const mkt = const mkt =
serumMarkets.find((m) => m.name === marketName) || serumMarkets.find((m) => m.name === marketName) ||
perpMarkets.find((m) => m.name === marketName) perpMarkets.find((m) => m.name === marketName)
if (mkt) { if (mkt) {
set((s) => { set((s) => {
s.selectedMarket.name = marketName s.selectedMarket.name = marketName
s.selectedMarket.current = mkt s.selectedMarket.current = mkt
s.tradeForm = {
...DEFAULT_TRADE_FORM,
price: getOraclePriceForMarket(group, mkt).toString(),
}
}) })
} }
} }

View File

@ -5,7 +5,7 @@ import { subscribeWithSelector } from 'zustand/middleware'
import { AnchorProvider, Wallet, web3 } from '@project-serum/anchor' import { AnchorProvider, Wallet, web3 } from '@project-serum/anchor'
import { Connection, Keypair, PublicKey } from '@solana/web3.js' import { Connection, Keypair, PublicKey } from '@solana/web3.js'
import { OpenOrders, Order } from '@project-serum/serum/lib/market' import { OpenOrders, Order } from '@project-serum/serum/lib/market'
import { Orderbook as SpotOrderBook } from '@project-serum/serum' import { Orderbook } from '@project-serum/serum'
import { Wallet as WalletAdapter } from '@solana/wallet-adapter-react' import { Wallet as WalletAdapter } from '@solana/wallet-adapter-react'
import { import {
MangoClient, MangoClient,
@ -33,7 +33,7 @@ import {
LAST_ACCOUNT_KEY, LAST_ACCOUNT_KEY,
OUTPUT_TOKEN_DEFAULT, OUTPUT_TOKEN_DEFAULT,
} from '../utils/constants' } from '../utils/constants'
import { Orderbook, SpotBalances } from 'types' import { OrderbookL2, SpotBalances } from 'types'
import spotBalancesUpdater from './spotBalancesUpdater' import spotBalancesUpdater from './spotBalancesUpdater'
import { PerpMarket } from '@blockworks-foundation/mango-v4/' import { PerpMarket } from '@blockworks-foundation/mango-v4/'
import perpPositionsUpdater from './perpPositionsUpdater' import perpPositionsUpdater from './perpPositionsUpdater'
@ -175,6 +175,26 @@ export interface TokenStatsItem {
// wallet_pk: '', // wallet_pk: '',
// } // }
interface TradeForm {
side: 'buy' | 'sell'
price: string | undefined
baseSize: string
quoteSize: string
tradeType: 'Market' | 'Limit'
postOnly: boolean
ioc: boolean
}
export const DEFAULT_TRADE_FORM: TradeForm = {
side: 'buy',
price: undefined,
baseSize: '',
quoteSize: '',
tradeType: 'Limit',
postOnly: false,
ioc: false,
}
export type MangoStore = { export type MangoStore = {
activityFeed: { activityFeed: {
feed: Array<DepositWithdrawFeedItem | LiquidationFeedItem> feed: Array<DepositWithdrawFeedItem | LiquidationFeedItem>
@ -213,9 +233,9 @@ export type MangoStore = {
name: string name: string
current: Serum3Market | PerpMarket | undefined current: Serum3Market | PerpMarket | undefined
fills: any fills: any
bidsAccount: BookSide | SpotOrderBook | undefined bidsAccount: BookSide | Orderbook | undefined
asksAccount: BookSide | SpotOrderBook | undefined asksAccount: BookSide | Orderbook | undefined
orderbook: Orderbook orderbook: OrderbookL2
markPrice: number markPrice: number
} }
serumMarkets: Serum3Market[] serumMarkets: Serum3Market[]
@ -243,15 +263,7 @@ export type MangoStore = {
loading: boolean loading: boolean
data: TokenStatsItem[] data: TokenStatsItem[]
} }
tradeForm: { tradeForm: TradeForm
side: 'buy' | 'sell'
price: string
baseSize: string
quoteSize: string
tradeType: 'Market' | 'Limit'
postOnly: boolean
ioc: boolean
}
wallet: { wallet: {
tokens: TokenAccount[] tokens: TokenAccount[]
nfts: { nfts: {
@ -364,15 +376,7 @@ const mangoStore = create<MangoStore>()(
loading: false, loading: false,
data: [], data: [],
}, },
tradeForm: { tradeForm: DEFAULT_TRADE_FORM,
side: 'buy',
price: '',
baseSize: '',
quoteSize: '',
tradeType: 'Limit',
postOnly: false,
ioc: false,
},
wallet: { wallet: {
tokens: [], tokens: [],
nfts: { nfts: {
@ -673,6 +677,9 @@ const mangoStore = create<MangoStore>()(
const set = get().set const set = get().set
const client = get().client const client = get().client
const group = get().group const group = get().group
if (!providedMangoAccount) {
await get().actions.reloadMangoAccount()
}
const mangoAccount = const mangoAccount =
providedMangoAccount || get().mangoAccount.current providedMangoAccount || get().mangoAccount.current

View File

@ -11,7 +11,7 @@ export interface ChartTradeType {
marketAddress: string marketAddress: string
} }
export interface Orderbook { export interface OrderbookL2 {
bids: number[][] bids: number[][]
asks: number[][] asks: number[][]
} }

View File

@ -1,7 +1,7 @@
import { Orderbook } from 'types' import { OrderbookL2 } from 'types'
export const calculateMarketPrice = ( export const calculateLimitPriceForMarketOrder = (
orderBook: Orderbook, orderBook: OrderbookL2,
size: number, size: number,
side: 'buy' | 'sell' side: 'buy' | 'sell'
): number => { ): number => {
@ -29,7 +29,7 @@ export const calculateMarketPrice = (
} }
export const calculateSlippage = ( export const calculateSlippage = (
orderBook: Orderbook, orderBook: OrderbookL2,
size: number, size: number,
side: 'buy' | 'sell', side: 'buy' | 'sell',
markPrice: number markPrice: number
@ -39,7 +39,11 @@ export const calculateSlippage = (
const referencePrice = bb && ba ? (bb + ba) / 2 : markPrice const referencePrice = bb && ba ? (bb + ba) / 2 : markPrice
if (Number(size)) { if (Number(size)) {
const estimatedPrice = calculateMarketPrice(orderBook, Number(size), side) const estimatedPrice = calculateLimitPriceForMarketOrder(
orderBook,
Number(size),
side
)
const slippageAbs = const slippageAbs =
Number(size) > 0 ? Math.abs(estimatedPrice - referencePrice) : 0 Number(size) > 0 ? Math.abs(estimatedPrice - referencePrice) : 0