wip
This commit is contained in:
parent
44b827da32
commit
1bf1514cc0
|
@ -14,6 +14,7 @@ import { OUTPUT_TOKEN_DEFAULT } from 'utils/constants'
|
|||
import { NUMBER_FORMAT_CLASSNAMES } from './MarketSwapForm'
|
||||
import InlineNotification from '@components/shared/InlineNotification'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import { SwapFormTokenListType } from './SwapFormTokenList'
|
||||
|
||||
const BuyTokenInput = ({
|
||||
error,
|
||||
|
@ -25,7 +26,7 @@ const BuyTokenInput = ({
|
|||
error?: string
|
||||
handleAmountOutChange: (e: NumberFormatValues, info: SourceInfo) => void
|
||||
loading?: boolean
|
||||
setShowTokenSelect: Dispatch<SetStateAction<'input' | 'output' | undefined>>
|
||||
setShowTokenSelect: Dispatch<SetStateAction<SwapFormTokenListType>>
|
||||
handleRepay?: (amountOut: string) => void
|
||||
}) => {
|
||||
const { t } = useTranslation('common')
|
||||
|
|
|
@ -26,8 +26,8 @@ import SwapSlider from './SwapSlider'
|
|||
import PercentageSelectButtons from './PercentageSelectButtons'
|
||||
import { floorToDecimal, formatCurrencyValue } from 'utils/numbers'
|
||||
import { withValueLimit } from './MarketSwapForm'
|
||||
import SellTokenInput from './SellTokenInput'
|
||||
import BuyTokenInput from './BuyTokenInput'
|
||||
import ReduceInputTokenInput from './ReduceInputTokenInput'
|
||||
import ReduceOutputTokenInput from './ReduceOutputTokenInput'
|
||||
import { notify } from 'utils/notifications'
|
||||
import * as sentry from '@sentry/nextjs'
|
||||
import { isMangoError } from 'types'
|
||||
|
@ -45,12 +45,13 @@ import DepositWithdrawModal from '@components/modals/DepositWithdrawModal'
|
|||
import useRemainingBorrowsInPeriod from 'hooks/useRemainingBorrowsInPeriod'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { SwapFormTokenListType } from './SwapFormTokenList'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
type LimitSwapFormProps = {
|
||||
showTokenSelect: 'input' | 'output' | undefined
|
||||
setShowTokenSelect: Dispatch<SetStateAction<'input' | 'output' | undefined>>
|
||||
showTokenSelect: SwapFormTokenListType
|
||||
setShowTokenSelect: Dispatch<SetStateAction<SwapFormTokenListType>>
|
||||
}
|
||||
|
||||
type LimitSwapForm = {
|
||||
|
@ -230,12 +231,20 @@ const LimitSwapForm = ({
|
|||
return triggerDifference
|
||||
}, [quotePrice, triggerPrice])
|
||||
|
||||
const handleTokenSelect = (type: 'input' | 'output') => {
|
||||
const handleTokenSelect = (type: SwapFormTokenListType) => {
|
||||
setShowTokenSelect(type)
|
||||
setFormErrors({})
|
||||
setTriggerPrice('')
|
||||
}
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!mangoAccount || !inputBank) {
|
||||
return
|
||||
}
|
||||
const inputPos = mangoAccount.getTokenBalanceUi(inputBank)
|
||||
setAnimateSwitchArrow(() => (inputPos > 0 ? 0 : 1))
|
||||
}, [inputBank, mangoAccount])
|
||||
|
||||
const hasBorrowToRepay = useMemo(() => {
|
||||
if (
|
||||
// orderType !== OrderTypes.REPAY_BORROW ||
|
||||
|
@ -480,47 +489,6 @@ const LimitSwapForm = ({
|
|||
[amountInFormValue, flipPrices, setFormErrors, setTriggerPrice],
|
||||
)
|
||||
|
||||
const handleSwitchTokens = useCallback(() => {
|
||||
if (!inputBank || !outputBank) return
|
||||
setFormErrors({})
|
||||
set((s) => {
|
||||
s.swap.inputBank = outputBank
|
||||
s.swap.outputBank = inputBank
|
||||
})
|
||||
const multiplier = getOrderTypeMultiplier(orderType, flipPrices)
|
||||
const price = flipPrices
|
||||
? floorToDecimal(
|
||||
(inputBank.uiPrice / outputBank.uiPrice) * multiplier,
|
||||
outputBank.mintDecimals,
|
||||
).toString()
|
||||
: floorToDecimal(
|
||||
(outputBank.uiPrice / inputBank.uiPrice) * multiplier,
|
||||
inputBank.mintDecimals,
|
||||
).toString()
|
||||
setTriggerPrice(price)
|
||||
|
||||
if (amountInAsDecimal?.gt(0)) {
|
||||
const amountOut = getAmountOut(
|
||||
amountInAsDecimal.toString(),
|
||||
flipPrices,
|
||||
price,
|
||||
)
|
||||
setAmountOutFormValue(amountOut.toString())
|
||||
}
|
||||
setAnimateSwitchArrow(
|
||||
(prevanimateSwitchArrow) => prevanimateSwitchArrow + 1,
|
||||
)
|
||||
}, [
|
||||
amountInAsDecimal,
|
||||
flipPrices,
|
||||
inputBank,
|
||||
orderType,
|
||||
outputBank,
|
||||
setAmountInFormValue,
|
||||
setFormErrors,
|
||||
triggerPrice,
|
||||
])
|
||||
|
||||
const handlePlaceStopLoss = useCallback(async () => {
|
||||
const invalidFields = isFormValid({
|
||||
amountIn: amountInAsDecimal.toNumber(),
|
||||
|
@ -760,11 +728,11 @@ const LimitSwapForm = ({
|
|||
|
||||
return (
|
||||
<>
|
||||
<SellTokenInput
|
||||
<ReduceInputTokenInput
|
||||
className="rounded-b-none"
|
||||
error={formErrors.amountIn}
|
||||
handleAmountInChange={handleAmountInChange}
|
||||
setShowTokenSelect={() => handleTokenSelect('input')}
|
||||
setShowTokenSelect={() => handleTokenSelect('reduce-input')}
|
||||
handleMax={handleMax}
|
||||
isTriggerOrder
|
||||
/>
|
||||
|
@ -867,24 +835,19 @@ const LimitSwapForm = ({
|
|||
) : null}
|
||||
</div>
|
||||
<div className="my-2 flex justify-center">
|
||||
<button
|
||||
className="rounded-full border border-th-fgd-4 p-1.5 text-th-fgd-3 focus-visible:border-th-active md:hover:border-th-active md:hover:text-th-active"
|
||||
onClick={handleSwitchTokens}
|
||||
>
|
||||
<ArrowDownIcon
|
||||
className="h-5 w-5"
|
||||
style={
|
||||
animateSwitchArrow % 2 == 0
|
||||
? { transform: 'rotate(0deg)' }
|
||||
: { transform: 'rotate(360deg)' }
|
||||
}
|
||||
/>
|
||||
</button>
|
||||
<ArrowDownIcon
|
||||
className="h-5 w-5"
|
||||
style={
|
||||
animateSwitchArrow % 2 == 0
|
||||
? { transform: 'rotate(0deg)' }
|
||||
: { transform: 'rotate(180deg)' }
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<BuyTokenInput
|
||||
<ReduceOutputTokenInput
|
||||
error={formErrors.hasBorrows}
|
||||
handleAmountOutChange={handleAmountOutChange}
|
||||
setShowTokenSelect={() => handleTokenSelect('output')}
|
||||
setShowTokenSelect={() => handleTokenSelect('reduce-output')}
|
||||
handleRepay={
|
||||
// orderType === OrderTypes.REPAY_BORROW ?
|
||||
handleRepay
|
||||
|
|
|
@ -38,11 +38,12 @@ import useRemainingBorrowsInPeriod from 'hooks/useRemainingBorrowsInPeriod'
|
|||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { formatCurrencyValue } from 'utils/numbers'
|
||||
import { SwapFormTokenListType } from './SwapFormTokenList'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
type MarketSwapFormProps = {
|
||||
setShowTokenSelect: Dispatch<SetStateAction<'input' | 'output' | undefined>>
|
||||
setShowTokenSelect: Dispatch<SetStateAction<SwapFormTokenListType>>
|
||||
}
|
||||
|
||||
const MAX_DIGITS = 11
|
||||
|
|
|
@ -3,22 +3,20 @@ import mangoStore from '@store/mangoStore'
|
|||
import Decimal from 'decimal.js'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
import { useTokenMax } from './useTokenMax'
|
||||
import { TokenMaxResults } from './useTokenMax'
|
||||
|
||||
const MaxSwapAmount = ({
|
||||
setAmountIn,
|
||||
useMargin,
|
||||
maxAmount,
|
||||
}: {
|
||||
setAmountIn: (x: string) => void
|
||||
useMargin: boolean
|
||||
maxAmount: (useMargin: boolean) => TokenMaxResults
|
||||
}) => {
|
||||
const { t } = useTranslation('common')
|
||||
const mangoAccountLoading = mangoStore((s) => s.mangoAccount.initialLoad)
|
||||
const {
|
||||
amount: tokenMax,
|
||||
amountWithBorrow,
|
||||
decimals,
|
||||
} = useTokenMax(useMargin)
|
||||
const { amount: tokenMax, amountWithBorrow, decimals } = maxAmount(useMargin)
|
||||
|
||||
if (mangoAccountLoading) return null
|
||||
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
import TokenSelect from './TokenSelect'
|
||||
import NumberFormat, {
|
||||
NumberFormatValues,
|
||||
SourceInfo,
|
||||
} from 'react-number-format'
|
||||
import { formatCurrencyValue } from 'utils/numbers'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Dispatch, SetStateAction, useMemo } from 'react'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import { INPUT_TOKEN_DEFAULT } from 'utils/constants'
|
||||
import { NUMBER_FORMAT_CLASSNAMES, withValueLimit } from './MarketSwapForm'
|
||||
import MaxSwapAmount from './MaxSwapAmount'
|
||||
import useUnownedAccount from 'hooks/useUnownedAccount'
|
||||
import InlineNotification from '@components/shared/InlineNotification'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import { toUiDecimalsForQuote } from '@blockworks-foundation/mango-v4'
|
||||
import { SwapFormTokenListType } from './SwapFormTokenList'
|
||||
import { TokenMaxResults } from './useTokenMax'
|
||||
import Decimal from 'decimal.js'
|
||||
|
||||
const useAbsInputPosition = (): TokenMaxResults => {
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const { inputBank } = mangoStore((s) => s.swap)
|
||||
|
||||
if (!mangoAccount || !inputBank) {
|
||||
return {
|
||||
amount: new Decimal(0),
|
||||
amountWithBorrow: new Decimal(0),
|
||||
decimals: 6,
|
||||
}
|
||||
}
|
||||
|
||||
const amount = new Decimal(
|
||||
Math.abs(mangoAccount.getTokenBalanceUi(inputBank)),
|
||||
)
|
||||
return {
|
||||
decimals: inputBank.mintDecimals,
|
||||
amount: amount,
|
||||
amountWithBorrow: amount,
|
||||
}
|
||||
}
|
||||
|
||||
const ReduceInputTokenInput = ({
|
||||
handleAmountInChange,
|
||||
setShowTokenSelect,
|
||||
handleMax,
|
||||
className,
|
||||
error,
|
||||
isTriggerOrder,
|
||||
}: {
|
||||
handleAmountInChange: (e: NumberFormatValues, info: SourceInfo) => void
|
||||
setShowTokenSelect: Dispatch<SetStateAction<SwapFormTokenListType>>
|
||||
handleMax: (amountIn: string) => void
|
||||
className?: string
|
||||
error?: string
|
||||
isTriggerOrder?: boolean
|
||||
}) => {
|
||||
const { t } = useTranslation('common')
|
||||
const { mangoAccountAddress } = useMangoAccount()
|
||||
const { group } = useMangoGroup()
|
||||
const { isUnownedAccount } = useUnownedAccount()
|
||||
const {
|
||||
margin: useMargin,
|
||||
inputBank,
|
||||
amountIn: amountInFormValue,
|
||||
} = mangoStore((s) => s.swap)
|
||||
|
||||
const freeCollateral = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
return group && mangoAccount
|
||||
? toUiDecimalsForQuote(mangoAccount.getCollateralValue(group))
|
||||
: 10
|
||||
}, [mangoAccountAddress])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`grid grid-cols-2 rounded-t-xl bg-th-bkg-2 p-3 pb-2 ${className}`}
|
||||
>
|
||||
<div className="col-span-2 mb-2 flex items-center justify-between">
|
||||
<p className="text-th-fgd-2">{t('reduce')}</p>
|
||||
{!isUnownedAccount ? (
|
||||
<MaxSwapAmount
|
||||
useMargin={isTriggerOrder ? false : useMargin}
|
||||
setAmountIn={(v) => handleMax(v)}
|
||||
maxAmount={useAbsInputPosition}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<TokenSelect
|
||||
bank={
|
||||
inputBank || group?.banksMapByName.get(INPUT_TOKEN_DEFAULT)?.[0] // default to a user position
|
||||
}
|
||||
showTokenList={setShowTokenSelect}
|
||||
type="reduce-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative col-span-1">
|
||||
<NumberFormat
|
||||
inputMode="decimal"
|
||||
thousandSeparator=","
|
||||
allowNegative={false}
|
||||
isNumericString={true}
|
||||
decimalScale={inputBank?.mintDecimals || 6}
|
||||
name="amountIn"
|
||||
id="amountIn"
|
||||
className={NUMBER_FORMAT_CLASSNAMES}
|
||||
placeholder="0.00"
|
||||
value={amountInFormValue}
|
||||
onValueChange={handleAmountInChange}
|
||||
isAllowed={withValueLimit}
|
||||
/>
|
||||
{!isNaN(Number(amountInFormValue)) ? (
|
||||
<span className="absolute bottom-1.5 right-3 text-xxs text-th-fgd-4">
|
||||
{inputBank
|
||||
? formatCurrencyValue(
|
||||
inputBank.uiPrice * Number(amountInFormValue),
|
||||
)
|
||||
: '–'}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
{mangoAccountAddress && freeCollateral <= 0 ? (
|
||||
<div className="col-span-2 mt-1 flex justify-center">
|
||||
<InlineNotification
|
||||
type="warning"
|
||||
desc={t('swap:warning-no-collateral')}
|
||||
hideBorder
|
||||
hidePadding
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{error ? (
|
||||
<div className="col-span-2 mt-1 flex justify-center">
|
||||
<InlineNotification
|
||||
type="error"
|
||||
desc={error}
|
||||
hideBorder
|
||||
hidePadding
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReduceInputTokenInput
|
|
@ -0,0 +1,127 @@
|
|||
import MaxAmountButton from '@components/shared/MaxAmountButton'
|
||||
import TokenSelect from './TokenSelect'
|
||||
import Loading from '@components/shared/Loading'
|
||||
import NumberFormat, {
|
||||
NumberFormatValues,
|
||||
SourceInfo,
|
||||
} from 'react-number-format'
|
||||
import { floorToDecimal, formatCurrencyValue } from 'utils/numbers'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Dispatch, SetStateAction, useMemo } from 'react'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import { OUTPUT_TOKEN_DEFAULT } from 'utils/constants'
|
||||
import { NUMBER_FORMAT_CLASSNAMES } from './MarketSwapForm'
|
||||
import InlineNotification from '@components/shared/InlineNotification'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import { SwapFormTokenListType } from './SwapFormTokenList'
|
||||
|
||||
const ReduceOutputTokenInput = ({
|
||||
error,
|
||||
handleAmountOutChange,
|
||||
loading,
|
||||
setShowTokenSelect,
|
||||
handleRepay,
|
||||
}: {
|
||||
error?: string
|
||||
handleAmountOutChange: (e: NumberFormatValues, info: SourceInfo) => void
|
||||
loading?: boolean
|
||||
setShowTokenSelect: Dispatch<SetStateAction<SwapFormTokenListType>>
|
||||
handleRepay?: (amountOut: string) => void
|
||||
}) => {
|
||||
const { t } = useTranslation('common')
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const { group } = useMangoGroup()
|
||||
const {
|
||||
inputBank,
|
||||
outputBank,
|
||||
amountOut: amountOutFormValue,
|
||||
} = mangoStore((s) => s.swap)
|
||||
|
||||
const reducingLong =
|
||||
mangoAccount && inputBank
|
||||
? mangoAccount.getTokenBalanceUi(inputBank) > 0
|
||||
: false
|
||||
|
||||
const outputTokenBalanceBorrow = useMemo(() => {
|
||||
if (!outputBank || !mangoAccount) return 0
|
||||
const balance = mangoAccount.getTokenBalanceUi(outputBank)
|
||||
const roundedBalance = floorToDecimal(
|
||||
balance,
|
||||
outputBank.mintDecimals,
|
||||
).toNumber()
|
||||
return balance && balance < 0 ? Math.abs(roundedBalance).toString() : 0
|
||||
}, [mangoAccount, outputBank])
|
||||
|
||||
return (
|
||||
<div className="mb-2 grid grid-cols-2 rounded-xl bg-th-bkg-2 p-3">
|
||||
<div className="col-span-2 mb-2 flex items-end justify-between">
|
||||
<p className="text-th-fgd-2">
|
||||
{reducingLong ? t('producing') : t('by-selling')}
|
||||
</p>
|
||||
{handleRepay && outputTokenBalanceBorrow ? (
|
||||
<MaxAmountButton
|
||||
className="mb-0.5 text-xs"
|
||||
decimals={outputBank?.mintDecimals || 9}
|
||||
label={t('repay')}
|
||||
onClick={() => handleRepay(outputTokenBalanceBorrow)}
|
||||
value={outputTokenBalanceBorrow}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<TokenSelect
|
||||
bank={
|
||||
outputBank || group?.banksMapByName.get(OUTPUT_TOKEN_DEFAULT)?.[0]
|
||||
}
|
||||
showTokenList={setShowTokenSelect}
|
||||
type="reduce-output"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative col-span-1">
|
||||
{loading ? (
|
||||
<div className="flex h-[56px] w-full items-center justify-center rounded-l-none rounded-r-lg border-l border-th-bkg-2 bg-th-input-bkg">
|
||||
<Loading />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<NumberFormat
|
||||
inputMode="decimal"
|
||||
thousandSeparator=","
|
||||
allowNegative={false}
|
||||
isNumericString={true}
|
||||
decimalScale={outputBank?.mintDecimals || 6}
|
||||
name="amountOut"
|
||||
id="amountOut"
|
||||
className={NUMBER_FORMAT_CLASSNAMES}
|
||||
placeholder="0.00"
|
||||
value={amountOutFormValue}
|
||||
onValueChange={handleAmountOutChange}
|
||||
/>
|
||||
{!isNaN(Number(amountOutFormValue)) ? (
|
||||
<span className="absolute bottom-1.5 right-3 text-xxs text-th-fgd-4">
|
||||
{outputBank
|
||||
? formatCurrencyValue(
|
||||
outputBank.uiPrice * Number(amountOutFormValue),
|
||||
)
|
||||
: '–'}
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{error ? (
|
||||
<div className="col-span-2 mt-1 flex justify-center">
|
||||
<InlineNotification
|
||||
type="error"
|
||||
desc={error}
|
||||
hideBorder
|
||||
hidePadding
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReduceOutputTokenInput
|
|
@ -15,6 +15,8 @@ import useUnownedAccount from 'hooks/useUnownedAccount'
|
|||
import InlineNotification from '@components/shared/InlineNotification'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import { toUiDecimalsForQuote } from '@blockworks-foundation/mango-v4'
|
||||
import { SwapFormTokenListType } from './SwapFormTokenList'
|
||||
import { useTokenMax } from './useTokenMax'
|
||||
|
||||
const SellTokenInput = ({
|
||||
handleAmountInChange,
|
||||
|
@ -25,7 +27,7 @@ const SellTokenInput = ({
|
|||
isTriggerOrder,
|
||||
}: {
|
||||
handleAmountInChange: (e: NumberFormatValues, info: SourceInfo) => void
|
||||
setShowTokenSelect: Dispatch<SetStateAction<'input' | 'output' | undefined>>
|
||||
setShowTokenSelect: Dispatch<SetStateAction<SwapFormTokenListType>>
|
||||
handleMax: (amountIn: string) => void
|
||||
className?: string
|
||||
error?: string
|
||||
|
@ -59,6 +61,7 @@ const SellTokenInput = ({
|
|||
<MaxSwapAmount
|
||||
useMargin={isTriggerOrder ? false : useMargin}
|
||||
setAmountIn={(v) => handleMax(v)}
|
||||
maxAmount={useTokenMax}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
|
@ -20,13 +20,15 @@ import LimitSwapForm from './LimitSwapForm'
|
|||
import Switch from '@components/forms/Switch'
|
||||
import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||
import { useIsWhiteListed } from 'hooks/useIsWhiteListed'
|
||||
import { SwapFormTokenListType } from './SwapFormTokenList'
|
||||
|
||||
const set = mangoStore.getState().set
|
||||
|
||||
const SwapForm = () => {
|
||||
const { t } = useTranslation(['common', 'swap', 'trade'])
|
||||
const { data: isWhiteListed } = useIsWhiteListed()
|
||||
const [showTokenSelect, setShowTokenSelect] = useState<'input' | 'output'>()
|
||||
const [showTokenSelect, setShowTokenSelect] =
|
||||
useState<SwapFormTokenListType>()
|
||||
const [showSettings, setShowSettings] = useState(false)
|
||||
const [swapOrLimit, setSwapOrLimit] = useState('swap')
|
||||
const [, setSavedSwapMargin] = useLocalStorageState<boolean>(
|
||||
|
@ -149,7 +151,7 @@ const SwapForm = () => {
|
|||
<SwapFormTokenList
|
||||
onClose={() => setShowTokenSelect(undefined)}
|
||||
onTokenSelect={
|
||||
showTokenSelect === 'input'
|
||||
showTokenSelect === 'input' || showTokenSelect === 'reduce-input'
|
||||
? handleTokenInSelect
|
||||
: handleTokenOutSelect
|
||||
}
|
||||
|
|
|
@ -15,6 +15,13 @@ import { formatTokenSymbol } from 'utils/tokens'
|
|||
import TokenLogo from '@components/shared/TokenLogo'
|
||||
import Input from '@components/forms/Input'
|
||||
|
||||
export type SwapFormTokenListType =
|
||||
| 'input'
|
||||
| 'output'
|
||||
| 'reduce-input'
|
||||
| 'reduce-output'
|
||||
| undefined
|
||||
|
||||
const generateSearchTerm = (item: Token, searchValue: string) => {
|
||||
const normalizedSearchValue = searchValue.toLowerCase()
|
||||
const values = `${item.symbol} ${item.name}`.toLowerCase()
|
||||
|
@ -50,7 +57,7 @@ const TokenItem = ({
|
|||
token: TokenInfoWithAmounts
|
||||
onSubmit: (x: string) => void
|
||||
useMargin: boolean
|
||||
type: 'input' | 'output' | undefined
|
||||
type: SwapFormTokenListType
|
||||
}) => {
|
||||
const { t } = useTranslation('trade')
|
||||
const { address, symbol, name } = token
|
||||
|
@ -92,7 +99,7 @@ const TokenItem = ({
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{type === 'input' &&
|
||||
{(type === 'input' || type === 'reduce-input') &&
|
||||
token.amount &&
|
||||
token.amountWithBorrow &&
|
||||
token.decimals ? (
|
||||
|
@ -128,7 +135,7 @@ const SwapFormTokenList = ({
|
|||
}: {
|
||||
onClose: () => void
|
||||
onTokenSelect: (x: string) => void
|
||||
type: 'input' | 'output' | undefined
|
||||
type: SwapFormTokenListType
|
||||
useMargin: boolean
|
||||
}) => {
|
||||
const { t } = useTranslation(['common', 'search', 'swap'])
|
||||
|
@ -177,6 +184,37 @@ const SwapFormTokenList = ({
|
|||
: Number(b.amount) - Number(a.amount),
|
||||
)
|
||||
|
||||
return filteredSortedTokens
|
||||
} else if (
|
||||
mangoTokens?.length &&
|
||||
group &&
|
||||
mangoAccount &&
|
||||
outputBank &&
|
||||
inputBank &&
|
||||
type === 'reduce-input'
|
||||
) {
|
||||
const filteredSortedTokens = mangoTokens
|
||||
.map((token) => {
|
||||
const tokenBank = group.getFirstBankByMint(
|
||||
new PublicKey(token.address),
|
||||
)
|
||||
const uiAmount = mangoAccount.getTokenBalanceUi(tokenBank)
|
||||
const uiDollarValue = uiAmount * tokenBank.uiPrice
|
||||
console.log(tokenBank)
|
||||
return {
|
||||
...token,
|
||||
amount: new Decimal(uiAmount),
|
||||
amountWithBorrow: new Decimal(uiAmount),
|
||||
absDollarValue: Math.abs(uiDollarValue),
|
||||
decimals: inputBank.mintDecimals,
|
||||
}
|
||||
})
|
||||
.filter(
|
||||
(token) =>
|
||||
token.symbol !== outputBank?.name && token.absDollarValue > 0.0001,
|
||||
)
|
||||
.sort((a, b) => b.absDollarValue - a.absDollarValue)
|
||||
|
||||
return filteredSortedTokens
|
||||
} else if (mangoTokens?.length) {
|
||||
const filteredTokens = mangoTokens
|
||||
|
@ -212,6 +250,8 @@ const SwapFormTokenList = ({
|
|||
? t('swap:you-sell')
|
||||
: type === 'output'
|
||||
? t('swap:you-buy')
|
||||
: type === 'reduce-input'
|
||||
? t('swap:you-reduce')
|
||||
: ''}
|
||||
</p>
|
||||
<IconButton
|
||||
|
|
|
@ -4,18 +4,31 @@ import { Bank } from '@blockworks-foundation/mango-v4'
|
|||
import { Dispatch, SetStateAction } from 'react'
|
||||
import { formatTokenSymbol } from 'utils/tokens'
|
||||
import TokenLogo from '@components/shared/TokenLogo'
|
||||
import { SwapFormTokenListType } from './SwapFormTokenList'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
|
||||
type TokenSelectProps = {
|
||||
bank: Bank | undefined
|
||||
showTokenList: Dispatch<SetStateAction<'input' | 'output' | undefined>>
|
||||
type: 'input' | 'output'
|
||||
showTokenList: Dispatch<SetStateAction<SwapFormTokenListType>>
|
||||
type: SwapFormTokenListType
|
||||
}
|
||||
|
||||
const TokenSelect = ({ bank, showTokenList, type }: TokenSelectProps) => {
|
||||
const { group } = useMangoGroup()
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
|
||||
if (!group) return null
|
||||
|
||||
let posType = ''
|
||||
if (type === 'reduce-input' && mangoAccount && bank) {
|
||||
const uiPos = mangoAccount.getTokenBalanceUi(bank)
|
||||
if (uiPos > 0) {
|
||||
posType = 'long'
|
||||
} else if (uiPos < 0) {
|
||||
posType = 'short'
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={() => showTokenList(type)}
|
||||
|
@ -26,7 +39,7 @@ const TokenSelect = ({ bank, showTokenList, type }: TokenSelectProps) => {
|
|||
</div>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<div className="text-xl font-bold text-th-fgd-1">
|
||||
{formatTokenSymbol(bank!.name)}
|
||||
{formatTokenSymbol(bank!.name)} {posType}
|
||||
</div>
|
||||
<ChevronDownIcon className="h-6 w-6" />
|
||||
</div>
|
||||
|
|
|
@ -105,7 +105,7 @@ export const getTokenInMax = (
|
|||
}
|
||||
}
|
||||
|
||||
interface TokenMaxResults {
|
||||
export interface TokenMaxResults {
|
||||
amount: Decimal
|
||||
amountWithBorrow: Decimal
|
||||
decimals: number
|
||||
|
|
|
@ -352,6 +352,7 @@ export default function SpotMarketOrderSwapForm() {
|
|||
<MaxSwapAmount
|
||||
useMargin={savedCheckboxSettings.margin}
|
||||
setAmountIn={setAmountFromSlider}
|
||||
maxAmount={useTokenMax}
|
||||
/>
|
||||
) : null}
|
||||
<div className="flex flex-col">
|
||||
|
|
Loading…
Reference in New Issue