sort sell token list by max amount
This commit is contained in:
parent
0ccaf19e40
commit
6dab2b74cf
|
@ -229,6 +229,7 @@ const SwapForm = () => {
|
||||||
: handleTokenOutSelect
|
: handleTokenOutSelect
|
||||||
}
|
}
|
||||||
type={showTokenSelect}
|
type={showTokenSelect}
|
||||||
|
useMargin={useMargin}
|
||||||
/>
|
/>
|
||||||
</EnterBottomExitBottom>
|
</EnterBottomExitBottom>
|
||||||
<EnterBottomExitBottom
|
<EnterBottomExitBottom
|
||||||
|
|
|
@ -10,6 +10,8 @@ import {
|
||||||
XMarkIcon,
|
XMarkIcon,
|
||||||
} from '@heroicons/react/20/solid'
|
} from '@heroicons/react/20/solid'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import { floorToDecimal } from '../../utils/numbers'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
const generateSearchTerm = (item: Token, searchValue: string) => {
|
const generateSearchTerm = (item: Token, searchValue: string) => {
|
||||||
const normalizedSearchValue = searchValue.toLowerCase()
|
const normalizedSearchValue = searchValue.toLowerCase()
|
||||||
|
@ -40,17 +42,27 @@ const startSearch = (items: Token[], searchValue: string) => {
|
||||||
const TokenItem = ({
|
const TokenItem = ({
|
||||||
token,
|
token,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
useMargin,
|
||||||
|
type,
|
||||||
}: {
|
}: {
|
||||||
token: Token
|
token: Token
|
||||||
onSubmit: (x: string) => void
|
onSubmit: (x: string) => void
|
||||||
|
useMargin: boolean
|
||||||
|
type: string
|
||||||
}) => {
|
}) => {
|
||||||
const { address, symbol, logoURI, name } = token
|
const { address, symbol, logoURI, name } = token
|
||||||
|
|
||||||
|
const isDisabled =
|
||||||
|
(type === 'input' && useMargin && token.maxAmountWithBorrow!.eq(0)) ||
|
||||||
|
(type === 'input' && !useMargin && token.maxAmount!.eq(0))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
key={address}
|
key={address}
|
||||||
className="flex w-full cursor-pointer items-center justify-between rounded-md p-2 font-normal focus:bg-th-bkg-3 focus:outline-none md:hover:bg-th-bkg-4"
|
className="default-transition flex w-full cursor-pointer items-start justify-between rounded-md p-2 font-normal focus:bg-th-bkg-3 focus:outline-none disabled:cursor-not-allowed disabled:opacity-60 md:hover:bg-th-bkg-4"
|
||||||
onClick={() => onSubmit(address)}
|
onClick={() => onSubmit(address)}
|
||||||
|
disabled={isDisabled}
|
||||||
>
|
>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<picture>
|
<picture>
|
||||||
|
@ -59,9 +71,18 @@ const TokenItem = ({
|
||||||
</picture>
|
</picture>
|
||||||
<div className="ml-2.5">
|
<div className="ml-2.5">
|
||||||
<div className="text-left text-th-fgd-2">{symbol || 'unknown'}</div>
|
<div className="text-left text-th-fgd-2">{symbol || 'unknown'}</div>
|
||||||
<div className="text-left text-th-fgd-4">{name || 'unknown'}</div>
|
<div className="text-left text-xs text-th-fgd-4">
|
||||||
|
{name || 'unknown'}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{type === 'input' ? (
|
||||||
|
<p className="text-sm text-th-fgd-2">
|
||||||
|
{useMargin
|
||||||
|
? token.maxAmountWithBorrow!.toString()
|
||||||
|
: token.maxAmount!.toString()}
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -73,10 +94,12 @@ const SwapFormTokenList = ({
|
||||||
onClose,
|
onClose,
|
||||||
onTokenSelect,
|
onTokenSelect,
|
||||||
type,
|
type,
|
||||||
|
useMargin,
|
||||||
}: {
|
}: {
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
onTokenSelect: (x: string) => void
|
onTokenSelect: (x: string) => void
|
||||||
type: string
|
type: string
|
||||||
|
useMargin: boolean
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
|
@ -85,6 +108,8 @@ const SwapFormTokenList = ({
|
||||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||||
const inputBank = mangoStore((s) => s.swap.inputBank)
|
const inputBank = mangoStore((s) => s.swap.inputBank)
|
||||||
const outputBank = mangoStore((s) => s.swap.outputBank)
|
const outputBank = mangoStore((s) => s.swap.outputBank)
|
||||||
|
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
|
||||||
|
const group = mangoStore((s) => s.group)
|
||||||
|
|
||||||
const popularTokens = useMemo(() => {
|
const popularTokens = useMemo(() => {
|
||||||
return tokens.filter((token) => {
|
return tokens.filter((token) => {
|
||||||
|
@ -105,27 +130,70 @@ const SwapFormTokenList = ({
|
||||||
}, [onClose])
|
}, [onClose])
|
||||||
|
|
||||||
const tokenInfos = useMemo(() => {
|
const tokenInfos = useMemo(() => {
|
||||||
if (tokens?.length) {
|
if (
|
||||||
const filteredTokens = tokens.filter((token) => {
|
tokens?.length &&
|
||||||
if (type === 'input') {
|
group &&
|
||||||
return token.symbol === outputBank?.name ? false : true
|
mangoAccount &&
|
||||||
} else {
|
outputBank &&
|
||||||
return token.symbol === inputBank?.name ? false : true
|
type === 'input'
|
||||||
}
|
) {
|
||||||
})
|
const filteredSortedTokens = tokens
|
||||||
if (walletTokens?.length) {
|
.map((token) => {
|
||||||
const walletMints = walletTokens.map((tok) => tok.mint.toString())
|
const bank = group.banksMapByMint.get(token.address)![0]
|
||||||
return filteredTokens.sort(
|
const tokenBalance = floorToDecimal(
|
||||||
(a, b) =>
|
mangoAccount.getTokenBalanceUi(bank),
|
||||||
walletMints.indexOf(b.address) - walletMints.indexOf(a.address)
|
bank.mintDecimals
|
||||||
|
)
|
||||||
|
const maxAmountWithoutMargin = tokenBalance.gt(0)
|
||||||
|
? tokenBalance
|
||||||
|
: new Decimal(0)
|
||||||
|
const maxUiAmountWithBorrow = floorToDecimal(
|
||||||
|
mangoAccount?.getMaxSourceUiForTokenSwap(
|
||||||
|
group,
|
||||||
|
bank.mint,
|
||||||
|
outputBank.mint,
|
||||||
|
1
|
||||||
|
)!,
|
||||||
|
bank.mintDecimals
|
||||||
|
)
|
||||||
|
const inputBankVaultBalance = group.getTokenVaultBalanceByMintUi(
|
||||||
|
bank.mint
|
||||||
|
)
|
||||||
|
const maxAmount = useMargin
|
||||||
|
? Decimal.min(
|
||||||
|
maxAmountWithoutMargin,
|
||||||
|
inputBankVaultBalance,
|
||||||
|
maxUiAmountWithBorrow!
|
||||||
|
)
|
||||||
|
: Decimal.min(maxAmountWithoutMargin, inputBankVaultBalance)
|
||||||
|
|
||||||
|
const maxAmountWithBorrow = Decimal.min(
|
||||||
|
maxUiAmountWithBorrow!,
|
||||||
|
inputBankVaultBalance
|
||||||
|
)
|
||||||
|
return { ...token, maxAmount, maxAmountWithBorrow }
|
||||||
|
})
|
||||||
|
.filter((token) => (token.symbol === outputBank?.name ? false : true))
|
||||||
|
.sort((a, b) =>
|
||||||
|
useMargin
|
||||||
|
? Number(b.maxAmountWithBorrow) - Number(a.maxAmountWithBorrow)
|
||||||
|
: Number(b.maxAmount) - Number(a.maxAmount)
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
return filteredTokens
|
return filteredSortedTokens
|
||||||
}
|
} else if (tokens?.length) {
|
||||||
|
const filteredTokens = tokens
|
||||||
|
.map((token) => ({
|
||||||
|
...token,
|
||||||
|
maxAmount: new Decimal(0),
|
||||||
|
maxAmountWithBorrow: new Decimal(0),
|
||||||
|
}))
|
||||||
|
.filter((token) => (token.symbol === inputBank?.name ? false : true))
|
||||||
|
return filteredTokens
|
||||||
} else {
|
} else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}, [tokens, walletTokens, inputBank, outputBank])
|
}, [tokens, walletTokens, inputBank, outputBank, mangoAccount, group])
|
||||||
|
|
||||||
const handleUpdateSearch = (e: ChangeEvent<HTMLInputElement>) => {
|
const handleUpdateSearch = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
setSearch(e.target.value)
|
setSearch(e.target.value)
|
||||||
|
@ -139,7 +207,9 @@ const SwapFormTokenList = ({
|
||||||
<IconButton className="absolute top-2 right-2" onClick={onClose} hideBg>
|
<IconButton className="absolute top-2 right-2" onClick={onClose} hideBg>
|
||||||
<XMarkIcon className="h-5 w-5" />
|
<XMarkIcon className="h-5 w-5" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<div className="flex items-center text-th-fgd-4">
|
{/* No need for search/popular tokens until we have more tokens */}
|
||||||
|
|
||||||
|
{/* <div className="flex items-center text-th-fgd-4">
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search by token or paste address"
|
placeholder="Search by token or paste address"
|
||||||
|
@ -180,14 +250,22 @@ const SwapFormTokenList = ({
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null} */}
|
||||||
<div className="my-2 border-t border-th-bkg-4"></div>
|
{/* <div className="my-2 border-t border-th-bkg-4"></div> */}
|
||||||
|
<div className="mb-2 flex justify-between rounded bg-th-bkg-3 p-2">
|
||||||
|
<p className="text-xs text-th-fgd-4">{t('token')}</p>
|
||||||
|
{type === 'input' ? (
|
||||||
|
<p className="text-xs text-th-fgd-4">{t('max')}</p>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
<div className="overflow-auto">
|
<div className="overflow-auto">
|
||||||
{sortedTokens.map((token) => (
|
{sortedTokens.map((token) => (
|
||||||
<TokenItem
|
<TokenItem
|
||||||
key={token.address}
|
key={token.address}
|
||||||
token={token}
|
token={token}
|
||||||
onSubmit={onTokenSelect}
|
onSubmit={onTokenSelect}
|
||||||
|
useMargin={useMargin}
|
||||||
|
type={type}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { RouteInfo } from '@jup-ag/core'
|
import { RouteInfo } from '@jup-ag/core'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
export type Routes = {
|
export type Routes = {
|
||||||
routesInfos: RouteInfo[]
|
routesInfos: RouteInfo[]
|
||||||
|
@ -16,4 +17,6 @@ export interface Token {
|
||||||
extensions?: {
|
extensions?: {
|
||||||
coingeckoId: string
|
coingeckoId: string
|
||||||
}
|
}
|
||||||
|
maxAmount?: Decimal
|
||||||
|
maxAmountWithBorrow?: Decimal
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue