move leverage calculation to components

This commit is contained in:
saml33 2022-12-26 22:58:17 +11:00
parent 201a8ad62a
commit ea2ef43b41
6 changed files with 249 additions and 124 deletions

View File

@ -33,14 +33,13 @@ import PerpButtonGroup from './PerpButtonGroup'
import SolBalanceWarnings from '@components/shared/SolBalanceWarnings'
import useJupiterMints from 'hooks/useJupiterMints'
import useSelectedMarket from 'hooks/useSelectedMarket'
import { getDecimalCount, trimDecimals } from 'utils/numbers'
import { getDecimalCount } from 'utils/numbers'
import LogoWithFallback from '@components/shared/LogoWithFallback'
import useIpAddress from 'hooks/useIpAddress'
import ButtonGroup from '@components/forms/ButtonGroup'
import TradeSummary from './TradeSummary'
import useMangoAccount from 'hooks/useMangoAccount'
import MaxAmountButton from '@components/shared/MaxAmountButton'
import { FadeInFadeOut } from '@components/shared/Transitions'
import MaxSizeButton from './MaxSizeButton'
const set = mangoStore.getState().set
@ -233,42 +232,6 @@ const AdvancedTradeForm = () => {
}
}, [oraclePrice, selectedMarket, tickDecimals, tradeForm])
const leverageMax = useMemo(() => {
const group = mangoStore.getState().group
if (!mangoAccount || !group || !selectedMarket) return 100
try {
if (selectedMarket instanceof Serum3Market) {
if (tradeForm.side === 'buy') {
return mangoAccount.getMaxQuoteForSerum3BidUi(
group,
selectedMarket.serumMarketExternal
)
} else {
return mangoAccount.getMaxBaseForSerum3AskUi(
group,
selectedMarket.serumMarketExternal
)
}
} else {
if (tradeForm.side === 'buy') {
return mangoAccount.getMaxQuoteForPerpBidUi(
group,
selectedMarket.perpMarketIndex
)
} else {
return mangoAccount.getMaxBaseForPerpAskUi(
group,
selectedMarket.perpMarketIndex
)
}
}
} catch (e) {
console.error('Error calculating max leverage: spot btn group: ', e)
return 0
}
}, [mangoAccount, tradeForm.side, selectedMarket])
const handlePlaceOrder = useCallback(async () => {
const client = mangoStore.getState().client
const group = mangoStore.getState().group
@ -372,59 +335,6 @@ const AdvancedTradeForm = () => {
return minOrderDecimals
}, [selectedMarket])
const handleMax = useCallback(() => {
const set = mangoStore.getState().set
set((state) => {
if (tradeForm.side === 'buy') {
state.tradeForm.quoteSize = trimDecimals(
leverageMax,
tickDecimals
).toFixed(tickDecimals)
if (tradeForm.tradeType === 'Market' || !tradeForm.price) {
state.tradeForm.baseSize = trimDecimals(
leverageMax / oraclePrice,
minOrderDecimals
).toFixed(minOrderDecimals)
} else {
state.tradeForm.baseSize = trimDecimals(
leverageMax / parseFloat(tradeForm.price),
minOrderDecimals
).toFixed(minOrderDecimals)
}
} else {
state.tradeForm.baseSize = trimDecimals(
leverageMax,
tickDecimals
).toFixed(tickDecimals)
if (tradeForm.tradeType === 'Market' || !tradeForm.price) {
state.tradeForm.quoteSize = trimDecimals(
leverageMax * oraclePrice,
minOrderDecimals
).toFixed(minOrderDecimals)
} else {
state.tradeForm.quoteSize = trimDecimals(
leverageMax * parseFloat(tradeForm.price),
minOrderDecimals
).toFixed(minOrderDecimals)
}
}
})
}, [leverageMax, tradeForm])
const maxAmount = useMemo(() => {
if (!tradeForm.price) return '0'
if (tradeForm.side === 'buy') {
return trimDecimals(
leverageMax / parseFloat(tradeForm.price),
tickDecimals
).toFixed(tickDecimals)
} else {
return trimDecimals(leverageMax, minOrderDecimals).toFixed(
minOrderDecimals
)
}
}, [leverageMax, minOrderDecimals, tickDecimals, tradeForm])
return (
<div>
<div className="mt-1.5 px-2 md:mt-0 md:border-t md:border-th-bkg-3 md:px-4 md:pt-5 lg:mt-5 lg:border-t-0 lg:pt-0">
@ -481,17 +391,10 @@ const AdvancedTradeForm = () => {
</div>
</>
) : null}
<div className="mb-2 mt-3 flex items-center justify-between">
<p className="text-xs text-th-fgd-3">{t('trade:size')}</p>
<FadeInFadeOut show={!!tradeForm.price}>
<MaxAmountButton
className="text-xs"
label={t('max')}
onClick={handleMax}
value={maxAmount}
/>
</FadeInFadeOut>
</div>
<MaxSizeButton
minOrderDecimals={minOrderDecimals}
tickDecimals={tickDecimals}
/>
<div className="flex flex-col">
<div className="default-transition flex items-center rounded-md rounded-b-none border border-th-input-border bg-th-input-bkg p-2 text-sm font-bold text-th-fgd-1 md:hover:z-10 md:hover:border-th-input-border-hover lg:text-base">
<div className="h-5 w-5 flex-shrink-0">
@ -556,26 +459,22 @@ const AdvancedTradeForm = () => {
{selectedMarket instanceof Serum3Market ? (
tradeFormSizeUi === 'slider' ? (
<SpotSlider
max={leverageMax}
minOrderDecimals={minOrderDecimals}
tickDecimals={tickDecimals}
/>
) : (
<SpotButtonGroup
max={leverageMax}
minOrderDecimals={minOrderDecimals}
tickDecimals={tickDecimals}
/>
)
) : tradeFormSizeUi === 'slider' ? (
<PerpSlider
max={leverageMax}
minOrderDecimals={minOrderDecimals}
tickDecimals={tickDecimals}
/>
) : (
<PerpButtonGroup
max={leverageMax}
minOrderDecimals={minOrderDecimals}
tickDecimals={tickDecimals}
/>

View File

@ -0,0 +1,127 @@
import { Serum3Market } from '@blockworks-foundation/mango-v4'
import MaxAmountButton from '@components/shared/MaxAmountButton'
import { FadeInFadeOut } from '@components/shared/Transitions'
import mangoStore from '@store/mangoStore'
import useMangoAccount from 'hooks/useMangoAccount'
import useSelectedMarket from 'hooks/useSelectedMarket'
import { useTranslation } from 'next-i18next'
import { useCallback, useMemo } from 'react'
import { trimDecimals } from 'utils/numbers'
const MaxSizeButton = ({
minOrderDecimals,
tickDecimals,
}: {
minOrderDecimals: number
tickDecimals: number
}) => {
const { t } = useTranslation(['common', 'trade'])
const { mangoAccount } = useMangoAccount()
const { selectedMarket, price: oraclePrice } = useSelectedMarket()
const tradeForm = mangoStore((s) => s.tradeForm)
const leverageMax = useMemo(() => {
const group = mangoStore.getState().group
if (!mangoAccount || !group || !selectedMarket) return 0
try {
if (selectedMarket instanceof Serum3Market) {
if (tradeForm.side === 'buy') {
return mangoAccount.getMaxQuoteForSerum3BidUi(
group,
selectedMarket.serumMarketExternal
)
} else {
return mangoAccount.getMaxBaseForSerum3AskUi(
group,
selectedMarket.serumMarketExternal
)
}
} else {
if (tradeForm.side === 'buy') {
return mangoAccount.getMaxQuoteForPerpBidUi(
group,
selectedMarket.perpMarketIndex
)
} else {
return mangoAccount.getMaxBaseForPerpAskUi(
group,
selectedMarket.perpMarketIndex
)
}
}
} catch (e) {
console.error('Error calculating max leverage: spot btn group: ', e)
return 0
}
}, [mangoAccount, tradeForm.side, selectedMarket])
const handleMax = useCallback(() => {
const set = mangoStore.getState().set
set((state) => {
if (tradeForm.side === 'buy') {
state.tradeForm.quoteSize = trimDecimals(
leverageMax,
tickDecimals
).toFixed(tickDecimals)
if (tradeForm.tradeType === 'Market' || !tradeForm.price) {
state.tradeForm.baseSize = trimDecimals(
leverageMax / oraclePrice,
minOrderDecimals
).toFixed(minOrderDecimals)
} else {
state.tradeForm.baseSize = trimDecimals(
leverageMax / parseFloat(tradeForm.price),
minOrderDecimals
).toFixed(minOrderDecimals)
}
} else {
state.tradeForm.baseSize = trimDecimals(
leverageMax,
tickDecimals
).toFixed(tickDecimals)
if (tradeForm.tradeType === 'Market' || !tradeForm.price) {
state.tradeForm.quoteSize = trimDecimals(
leverageMax * oraclePrice,
minOrderDecimals
).toFixed(minOrderDecimals)
} else {
state.tradeForm.quoteSize = trimDecimals(
leverageMax * parseFloat(tradeForm.price),
minOrderDecimals
).toFixed(minOrderDecimals)
}
}
})
}, [leverageMax, tradeForm])
const maxAmount = useMemo(() => {
if (!tradeForm.price) return '0'
if (tradeForm.side === 'buy') {
return trimDecimals(
leverageMax / parseFloat(tradeForm.price),
tickDecimals
).toFixed(tickDecimals)
} else {
return trimDecimals(leverageMax, minOrderDecimals).toFixed(
minOrderDecimals
)
}
}, [leverageMax, minOrderDecimals, tickDecimals, tradeForm])
return (
<div className="mb-2 mt-3 flex items-center justify-between">
<p className="text-xs text-th-fgd-3">{t('trade:size')}</p>
<FadeInFadeOut show={!!tradeForm.price}>
<MaxAmountButton
className="text-xs"
label={t('max')}
onClick={handleMax}
value={maxAmount}
/>
</FadeInFadeOut>
</div>
)
}
export default MaxSizeButton

View File

@ -1,24 +1,52 @@
import { PerpMarket } from '@blockworks-foundation/mango-v4'
import ButtonGroup from '@components/forms/ButtonGroup'
import mangoStore from '@store/mangoStore'
import { useCallback, useState } from 'react'
import useMangoAccount from 'hooks/useMangoAccount'
import useSelectedMarket from 'hooks/useSelectedMarket'
import { useCallback, useMemo, useState } from 'react'
import { trimDecimals } from 'utils/numbers'
const PerpButtonGroup = ({
max,
minOrderDecimals,
tickDecimals,
}: {
max: number
minOrderDecimals: number
tickDecimals: number
}) => {
const side = mangoStore((s) => s.tradeForm.side)
const { selectedMarket } = useSelectedMarket()
const { mangoAccount } = useMangoAccount()
const [sizePercentage, setSizePercentage] = useState('')
const tradeFormPrice = mangoStore((s) => s.tradeForm.price)
const leverageMax = useMemo(() => {
const group = mangoStore.getState().group
if (!mangoAccount || !group || !selectedMarket) return 100
if (!(selectedMarket instanceof PerpMarket)) return 100
try {
if (side === 'buy') {
return mangoAccount.getMaxQuoteForPerpBidUi(
group,
selectedMarket.perpMarketIndex
)
} else {
return mangoAccount.getMaxBaseForPerpAskUi(
group,
selectedMarket.perpMarketIndex
)
}
} catch (e) {
console.error('Error calculating max leverage perp btn grp: ', e)
return 0
}
}, [side, selectedMarket, mangoAccount, tradeFormPrice])
const handleSizePercentage = useCallback(
(percentage: string) => {
const set = mangoStore.getState().set
setSizePercentage(percentage)
const size = max * (Number(percentage) / 100)
const size = leverageMax * (Number(percentage) / 100)
set((s) => {
if (s.tradeForm.side === 'buy') {
@ -48,7 +76,7 @@ const PerpButtonGroup = ({
}
})
},
[max, minOrderDecimals, tickDecimals]
[leverageMax, minOrderDecimals, tickDecimals]
)
return (

View File

@ -1,20 +1,21 @@
import { PerpMarket } from '@blockworks-foundation/mango-v4'
import LeverageSlider from '@components/shared/LeverageSlider'
import mangoStore from '@store/mangoStore'
import useMangoAccount from 'hooks/useMangoAccount'
import useSelectedMarket from 'hooks/useSelectedMarket'
import { useCallback, useMemo } from 'react'
import { trimDecimals } from 'utils/numbers'
const PerpSlider = ({
max,
minOrderDecimals,
tickDecimals,
}: {
max: number
minOrderDecimals: number
tickDecimals: number
}) => {
const side = mangoStore((s) => s.tradeForm.side)
const { selectedMarket, price: marketPrice } = useSelectedMarket()
const { mangoAccount } = useMangoAccount()
const tradeForm = mangoStore((s) => s.tradeForm)
const step = useMemo(() => {
@ -24,6 +25,29 @@ const PerpSlider = ({
return 0.01
}, [selectedMarket])
const leverageMax = useMemo(() => {
const group = mangoStore.getState().group
if (!mangoAccount || !group || !selectedMarket) return 100
if (!(selectedMarket instanceof PerpMarket)) return 100
try {
if (side === 'buy') {
return mangoAccount.getMaxQuoteForPerpBidUi(
group,
selectedMarket.perpMarketIndex
)
} else {
return mangoAccount.getMaxBaseForPerpAskUi(
group,
selectedMarket.perpMarketIndex
)
}
} catch (e) {
console.error('Error calculating max leverage for PerpSlider: ', e)
return 0
}
}, [side, selectedMarket, mangoAccount])
const handleSlide = useCallback(
(val: string) => {
const set = mangoStore.getState().set
@ -66,7 +90,7 @@ const PerpSlider = ({
? parseFloat(tradeForm.quoteSize)
: parseFloat(tradeForm.baseSize)
}
leverageMax={max}
leverageMax={leverageMax}
onChange={handleSlide}
step={step}
/>

View File

@ -1,16 +1,15 @@
import { Serum3Market } from '@blockworks-foundation/mango-v4'
import ButtonGroup from '@components/forms/ButtonGroup'
import mangoStore from '@store/mangoStore'
import useMangoAccount from 'hooks/useMangoAccount'
import useSelectedMarket from 'hooks/useSelectedMarket'
import { useCallback, useState } from 'react'
import { useCallback, useMemo, useState } from 'react'
import { trimDecimals } from 'utils/numbers'
const SpotButtonGroup = ({
max,
minOrderDecimals,
tickDecimals,
}: {
max: number
minOrderDecimals: number
tickDecimals: number
}) => {
@ -19,11 +18,34 @@ const SpotButtonGroup = ({
const { mangoAccount } = useMangoAccount()
const [sizePercentage, setSizePercentage] = useState('')
const leverageMax = useMemo(() => {
const group = mangoStore.getState().group
if (!mangoAccount || !group || !selectedMarket) return 100
if (!(selectedMarket instanceof Serum3Market)) return 100
try {
if (side === 'buy') {
return mangoAccount.getMaxQuoteForSerum3BidUi(
group,
selectedMarket.serumMarketExternal
)
} else {
return mangoAccount.getMaxBaseForSerum3AskUi(
group,
selectedMarket.serumMarketExternal
)
}
} catch (e) {
console.error('Error calculating max leverage: spot btn group: ', e)
return 0
}
}, [side, selectedMarket, mangoAccount])
const handleSizePercentage = useCallback(
(percentage: string) => {
const set = mangoStore.getState().set
setSizePercentage(percentage)
const size = max * (Number(percentage) / 100)
const size = leverageMax * (Number(percentage) / 100)
set((s) => {
if (s.tradeForm.side === 'buy') {

View File

@ -1,21 +1,46 @@
import { Serum3Market } from '@blockworks-foundation/mango-v4'
import LeverageSlider from '@components/shared/LeverageSlider'
import mangoStore from '@store/mangoStore'
import useMangoAccount from 'hooks/useMangoAccount'
import useSelectedMarket from 'hooks/useSelectedMarket'
import { useCallback } from 'react'
import { useCallback, useMemo } from 'react'
import { trimDecimals } from 'utils/numbers'
const SpotSlider = ({
max,
minOrderDecimals,
tickDecimals,
}: {
max: number
minOrderDecimals: number
tickDecimals: number
}) => {
const { price: marketPrice } = useSelectedMarket()
const side = mangoStore((s) => s.tradeForm.side)
const { selectedMarket, price: marketPrice } = useSelectedMarket()
const { mangoAccount } = useMangoAccount()
const tradeForm = mangoStore((s) => s.tradeForm)
const leverageMax = useMemo(() => {
const group = mangoStore.getState().group
if (!mangoAccount || !group || !selectedMarket) return 100
if (!(selectedMarket instanceof Serum3Market)) return 100
try {
if (side === 'buy') {
return mangoAccount.getMaxQuoteForSerum3BidUi(
group,
selectedMarket.serumMarketExternal
)
} else {
return mangoAccount.getMaxBaseForSerum3AskUi(
group,
selectedMarket.serumMarketExternal
)
}
} catch (e) {
console.error('Error calculating max leverage for spot slider: ', e)
return 0
}
}, [side, selectedMarket, mangoAccount])
const handleSlide = useCallback(
(val: string) => {
const set = mangoStore.getState().set
@ -58,7 +83,7 @@ const SpotSlider = ({
? parseFloat(tradeForm.quoteSize)
: parseFloat(tradeForm.baseSize)
}
leverageMax={max}
leverageMax={leverageMax}
onChange={handleSlide}
step={0.01}
/>