use jupiter api and hooks
This commit is contained in:
parent
5727d0bc7f
commit
203c571bc5
|
@ -1,8 +1,11 @@
|
|||
export const fetchChartData = async (
|
||||
baseTokenId: string,
|
||||
quoteTokenId: string,
|
||||
baseTokenId: string | undefined,
|
||||
quoteTokenId: string | undefined,
|
||||
daysToShow: number
|
||||
) => {
|
||||
console.log('fetching chart:', baseTokenId, quoteTokenId)
|
||||
|
||||
if (!baseTokenId || !quoteTokenId) return
|
||||
try {
|
||||
const [inputResponse, outputResponse] = await Promise.all([
|
||||
fetch(
|
||||
|
|
|
@ -1,42 +1,20 @@
|
|||
import { useEffect } from 'react'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import useInterval from '@components/shared/useInterval'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
import { useRouter } from 'next/router'
|
||||
import { MangoAccount } from '@blockworks-foundation/mango-v4'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
|
||||
const rehydrateStore = async () => {
|
||||
const actions = mangoStore.getState().actions
|
||||
actions.fetchGroup()
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
if (mangoAccount) {
|
||||
// actions.reloadMangoAccount()
|
||||
}
|
||||
}
|
||||
|
||||
const HydrateStore = () => {
|
||||
const actions = mangoStore((s) => s.actions)
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
|
||||
useInterval(() => {
|
||||
rehydrateStore()
|
||||
}, 5000)
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
await actions.fetchGroup()
|
||||
actions.fetchJupiterTokens()
|
||||
}
|
||||
fetchData()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (jupiterTokens.length) {
|
||||
actions.fetchCoingeckoPrices()
|
||||
}
|
||||
}, [jupiterTokens])
|
||||
}, [actions])
|
||||
|
||||
// watch selected Mango Account for changes
|
||||
useEffect(() => {
|
||||
|
|
|
@ -30,6 +30,7 @@ import Tooltip from './shared/Tooltip'
|
|||
import { formatTokenSymbol } from 'utils/tokens'
|
||||
import RepayModal from './modals/RepayModal'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useJupiterMints from '../hooks/useJupiterMints'
|
||||
|
||||
const TokenList = () => {
|
||||
const { t } = useTranslation(['common', 'token', 'trade'])
|
||||
|
@ -38,7 +39,7 @@ const TokenList = () => {
|
|||
const { mangoAccount } = useMangoAccount()
|
||||
const spotBalances = mangoStore((s) => s.mangoAccount.spotBalances)
|
||||
const group = mangoStore((s) => s.group)
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const totalInterestData = mangoStore(
|
||||
(s) => s.mangoAccount.stats.interestTotals.data
|
||||
)
|
||||
|
@ -136,8 +137,8 @@ const TokenList = () => {
|
|||
const oraclePrice = bank.uiPrice
|
||||
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
if (mangoTokens?.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank.mint.toString()
|
||||
)!.logoURI
|
||||
}
|
||||
|
@ -263,7 +264,7 @@ export default TokenList
|
|||
const MobileTokenListItem = ({ bank }: { bank: Bank }) => {
|
||||
const { t } = useTranslation(['common', 'token'])
|
||||
const [showTokenDetails, setShowTokenDetails] = useState(false)
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const spotBalances = mangoStore((s) => s.mangoAccount.spotBalances)
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const totalInterestData = mangoStore(
|
||||
|
@ -274,8 +275,8 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {
|
|||
const router = useRouter()
|
||||
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
if (mangoTokens?.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank.mint.toString()
|
||||
)!.logoURI
|
||||
}
|
||||
|
@ -420,7 +421,7 @@ const ActionsMenu = ({
|
|||
// const set = mangoStore.getState().set
|
||||
// const router = useRouter()
|
||||
// const { asPath } = router
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
|
||||
const handleShowActionModals = useCallback(
|
||||
(token: string, action: 'borrow' | 'deposit' | 'withdraw' | 'repay') => {
|
||||
|
@ -437,7 +438,7 @@ const ActionsMenu = ({
|
|||
)
|
||||
|
||||
// const handleBuy = useCallback(() => {
|
||||
// const outputTokenInfo = jupiterTokens.find(
|
||||
// const outputTokenInfo = mangoTokens.find(
|
||||
// (t: any) => t.address === bank.mint.toString()
|
||||
// )
|
||||
// set((s) => {
|
||||
|
@ -447,10 +448,10 @@ const ActionsMenu = ({
|
|||
// if (asPath === '/') {
|
||||
// router.push('/swap', undefined, { shallow: true })
|
||||
// }
|
||||
// }, [bank, router, asPath, set, jupiterTokens])
|
||||
// }, [bank, router, asPath, set, mangoTokens])
|
||||
|
||||
// const handleSell = useCallback(() => {
|
||||
// const inputTokenInfo = jupiterTokens.find(
|
||||
// const inputTokenInfo = mangoTokens.find(
|
||||
// (t: any) => t.address === bank.mint.toString()
|
||||
// )
|
||||
// set((s) => {
|
||||
|
@ -460,13 +461,12 @@ const ActionsMenu = ({
|
|||
// if (asPath === '/') {
|
||||
// router.push('/swap', undefined, { shallow: true })
|
||||
// }
|
||||
// }, [router, asPath, set, bank, jupiterTokens])
|
||||
// }, [router, asPath, set, bank, mangoTokens])
|
||||
|
||||
const logoURI = useMemo(() => {
|
||||
if (!bank || !jupiterTokens.length) return ''
|
||||
return jupiterTokens.find((t) => t.address === bank.mint.toString())
|
||||
?.logoURI
|
||||
}, [bank, jupiterTokens])
|
||||
if (!bank || !mangoTokens?.length) return ''
|
||||
return mangoTokens.find((t) => t.address === bank.mint.toString())?.logoURI
|
||||
}, [bank, mangoTokens])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -3,6 +3,7 @@ import Image from 'next/legacy/image'
|
|||
import { useMemo } from 'react'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { formatDecimal } from '../../utils/numbers'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
|
||||
const ActionTokenItem = ({
|
||||
bank,
|
||||
|
@ -18,17 +19,15 @@ const ActionTokenItem = ({
|
|||
showDepositRates?: boolean
|
||||
}) => {
|
||||
const { mint, name } = bank
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
|
||||
const logoUri = useMemo(() => {
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
(t) => t.address === mint.toString()
|
||||
)!.logoURI
|
||||
if (mangoTokens?.length) {
|
||||
logoURI = mangoTokens.find((t) => t.address === mint.toString())!.logoURI
|
||||
}
|
||||
return logoURI
|
||||
}, [mint, jupiterTokens])
|
||||
}, [mint, mangoTokens])
|
||||
|
||||
return (
|
||||
<button
|
||||
|
|
|
@ -28,6 +28,7 @@ import MaxAmountButton from '@components/shared/MaxAmountButton'
|
|||
import HealthImpactTokenChange from '@components/HealthImpactTokenChange'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
|
||||
interface BorrowModalProps {
|
||||
token?: string
|
||||
|
@ -45,7 +46,7 @@ function BorrowModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
)
|
||||
const [showTokenList, setShowTokenList] = useState(false)
|
||||
const [sizePercentage, setSizePercentage] = useState('')
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
|
||||
const bank = useMemo(() => {
|
||||
|
@ -55,13 +56,13 @@ function BorrowModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
|
||||
const logoUri = useMemo(() => {
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
if (mangoTokens?.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank?.mint.toString()
|
||||
)!.logoURI
|
||||
}
|
||||
return logoURI
|
||||
}, [jupiterTokens, bank])
|
||||
}, [mangoTokens, bank])
|
||||
|
||||
const tokenMax = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
|
|
|
@ -31,6 +31,7 @@ import Tooltip from '@components/shared/Tooltip'
|
|||
import HealthImpactTokenChange from '@components/HealthImpactTokenChange'
|
||||
import useSolBalance from 'hooks/useSolBalance'
|
||||
import SolBalanceWarnings from '@components/shared/SolBalanceWarnings'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
|
||||
interface DepositModalProps {
|
||||
token?: string
|
||||
|
@ -69,7 +70,7 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
)
|
||||
const [showTokenList, setShowTokenList] = useState(false)
|
||||
const [sizePercentage, setSizePercentage] = useState('')
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
|
||||
const bank = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
|
@ -78,13 +79,13 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
|
||||
const logoUri = useMemo(() => {
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
if (mangoTokens.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank?.mint.toString()
|
||||
)!.logoURI
|
||||
}
|
||||
return logoURI
|
||||
}, [bank?.mint, jupiterTokens])
|
||||
}, [bank?.mint, mangoTokens])
|
||||
|
||||
const { wallet } = useWallet()
|
||||
const walletTokens = mangoStore((s) => s.wallet.tokens)
|
||||
|
|
|
@ -29,6 +29,7 @@ import { walletBalanceForToken } from './DepositModal'
|
|||
import SolBalanceWarnings from '@components/shared/SolBalanceWarnings'
|
||||
import useSolBalance from 'hooks/useSolBalance'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
|
||||
interface RepayModalProps {
|
||||
token?: string
|
||||
|
@ -45,8 +46,8 @@ function RepayModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
const [selectedToken, setSelectedToken] = useState(token)
|
||||
const [showTokenList, setShowTokenList] = useState(false)
|
||||
const [sizePercentage, setSizePercentage] = useState('')
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { maxSolDeposit } = useSolBalance()
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
// const { maxSolDeposit } = useSolBalance()
|
||||
|
||||
const bank = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
|
@ -55,13 +56,13 @@ function RepayModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
|
||||
const logoUri = useMemo(() => {
|
||||
let logoURI
|
||||
if (jupiterTokens.length && bank) {
|
||||
logoURI = jupiterTokens.find(
|
||||
if (mangoTokens.length && bank) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank?.mint.toString()
|
||||
)!.logoURI
|
||||
}
|
||||
return logoURI
|
||||
}, [bank, jupiterTokens])
|
||||
}, [bank, mangoTokens])
|
||||
|
||||
const { wallet } = useWallet()
|
||||
const walletTokens = mangoStore((s) => s.wallet.tokens)
|
||||
|
|
|
@ -28,6 +28,7 @@ import { getMaxWithdrawForBank } from '../swap/useTokenMax'
|
|||
import MaxAmountButton from '@components/shared/MaxAmountButton'
|
||||
import HealthImpactTokenChange from '@components/HealthImpactTokenChange'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
|
||||
interface WithdrawModalProps {
|
||||
token?: string
|
||||
|
@ -45,7 +46,7 @@ function WithdrawModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
)
|
||||
const [showTokenList, setShowTokenList] = useState(false)
|
||||
const [sizePercentage, setSizePercentage] = useState('')
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
|
||||
const bank = useMemo(() => {
|
||||
|
@ -55,13 +56,13 @@ function WithdrawModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
|
||||
const logoUri = useMemo(() => {
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
if (mangoTokens.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank?.mint.toString()
|
||||
)!.logoURI
|
||||
}
|
||||
return logoURI
|
||||
}, [bank?.mint, jupiterTokens])
|
||||
}, [bank?.mint, mangoTokens])
|
||||
|
||||
const tokenMax = useMemo(() => {
|
||||
if (!bank || !mangoAccount || !group) return new Decimal(0)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Bank, Serum3Market } from '@blockworks-foundation/mango-v4'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import Decimal from 'decimal.js'
|
||||
|
@ -18,7 +19,7 @@ const BalancesTable = () => {
|
|||
const { mangoAccount } = useMangoAccount()
|
||||
const spotBalances = mangoStore((s) => s.mangoAccount.spotBalances)
|
||||
const group = mangoStore((s) => s.group)
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const { width } = useViewport()
|
||||
const showTableView = width ? width > breakpoints.md : false
|
||||
|
||||
|
@ -69,8 +70,8 @@ const BalancesTable = () => {
|
|||
const bank = value[0]
|
||||
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
if (mangoTokens.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank.mint.toString()
|
||||
)!.logoURI
|
||||
}
|
||||
|
@ -127,8 +128,8 @@ const BalancesTable = () => {
|
|||
const bank = value[0]
|
||||
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
if (mangoTokens.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank.mint.toString()
|
||||
)!.logoURI
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import ContentBox from '../shared/ContentBox'
|
|||
import Change from '../shared/Change'
|
||||
import MarketLogos from '@components/trade/MarketLogos'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useCoingecko } from 'hooks/useCoingecko'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
const SimpleAreaChart = dynamic(
|
||||
() => import('@components/shared/SimpleAreaChart'),
|
||||
{ ssr: false }
|
||||
|
@ -18,8 +20,7 @@ const SimpleAreaChart = dynamic(
|
|||
|
||||
const SpotMarketsTable = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data)
|
||||
const loadingCoingeckoPrices = mangoStore((s) => s.coingeckoPrices.loading)
|
||||
const { isLoading: loadingPrices, data: coingeckoPrices } = useCoingecko()
|
||||
const group = mangoStore((s) => s.group)
|
||||
const serumMarkets = mangoStore((s) => s.serumMarkets)
|
||||
const { theme } = useTheme()
|
||||
|
@ -74,7 +75,7 @@ const SpotMarketsTable = () => {
|
|||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{!loadingCoingeckoPrices ? (
|
||||
{!loadingPrices ? (
|
||||
chartData !== undefined ? (
|
||||
<SimpleAreaChart
|
||||
color={
|
||||
|
@ -127,22 +128,17 @@ export default SpotMarketsTable
|
|||
|
||||
const MobileSpotMarketItem = ({ market }: { market: Serum3Market }) => {
|
||||
const { t } = useTranslation('common')
|
||||
const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data)
|
||||
const loadingCoingeckoPrices = mangoStore((s) => s.coingeckoPrices.loading)
|
||||
const group = mangoStore((s) => s.group)
|
||||
const { isLoading: loadingPrices, data: coingeckoPrices } = useCoingecko()
|
||||
const { group } = useMangoGroup()
|
||||
const { theme } = useTheme()
|
||||
const bank = group?.getFirstBankByTokenIndex(market.baseTokenIndex)
|
||||
|
||||
const coingeckoData = useMemo(() => {
|
||||
if (!loadingCoingeckoPrices && bank) {
|
||||
return coingeckoPrices.find((asset) =>
|
||||
bank.name === 'soETH'
|
||||
? asset.symbol === 'ETH'
|
||||
: asset.symbol === bank?.name
|
||||
)
|
||||
if (!loadingPrices && bank) {
|
||||
return coingeckoPrices.find((asset) => asset.symbol === bank?.name)
|
||||
}
|
||||
return null
|
||||
}, [loadingCoingeckoPrices, bank])
|
||||
}, [loadingPrices, bank])
|
||||
|
||||
const change = useMemo(() => {
|
||||
if (coingeckoData) {
|
||||
|
@ -178,7 +174,7 @@ const MobileSpotMarketItem = ({ market }: { market: Serum3Market }) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{!loadingCoingeckoPrices ? (
|
||||
{!loadingPrices ? (
|
||||
chartData !== undefined ? (
|
||||
<SimpleAreaChart
|
||||
color={change >= 0 ? COLORS.GREEN[theme] : COLORS.RED[theme]}
|
||||
|
|
|
@ -18,12 +18,13 @@ import FlipNumbers from 'react-flip-numbers'
|
|||
import Tooltip from '@components/shared/Tooltip'
|
||||
import { Bank } from '@blockworks-foundation/mango-v4'
|
||||
import { useRouter } from 'next/router'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
|
||||
const TokenStats = () => {
|
||||
const { t } = useTranslation(['common', 'token'])
|
||||
const [showTokenDetails, setShowTokenDetails] = useState('')
|
||||
const group = mangoStore((s) => s.group)
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const { width } = useViewport()
|
||||
const showTableView = width ? width > breakpoints.md : false
|
||||
const router = useRouter()
|
||||
|
@ -141,8 +142,8 @@ const TokenStats = () => {
|
|||
const bank = value[0]
|
||||
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
if (mangoTokens.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank.mint.toString()
|
||||
)!.logoURI
|
||||
}
|
||||
|
@ -232,8 +233,8 @@ const TokenStats = () => {
|
|||
{banks.map(({ key, value }) => {
|
||||
const bank = value[0]
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
if (mangoTokens.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank.mint.toString()
|
||||
)!.logoURI
|
||||
}
|
||||
|
|
|
@ -6,9 +6,6 @@ import React, {
|
|||
useState,
|
||||
} from 'react'
|
||||
import { TransactionInstruction, PublicKey } from '@solana/web3.js'
|
||||
import { toUiDecimals } from '@blockworks-foundation/mango-v4'
|
||||
import { Jupiter, RouteInfo, TransactionFeeInfo } from '@jup-ag/core'
|
||||
import JSBI from 'jsbi'
|
||||
import Decimal from 'decimal.js'
|
||||
|
||||
import mangoStore from '@store/mangoStore'
|
||||
|
@ -31,10 +28,12 @@ import {
|
|||
} from '../../utils/numbers'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import useJupiterMints from '../../hooks/useJupiterMints'
|
||||
import { RouteInfo, TransactionFeeInfo } from 'types/jupiter'
|
||||
import useJupiterSwapData from './useJupiterSwapData'
|
||||
|
||||
type JupiterRouteInfoProps = {
|
||||
amountIn: Decimal
|
||||
jupiter: Jupiter | undefined
|
||||
onClose: () => void
|
||||
routes: RouteInfo[] | undefined
|
||||
selectedRoute: RouteInfo | undefined
|
||||
|
@ -43,14 +42,28 @@ type JupiterRouteInfoProps = {
|
|||
}
|
||||
|
||||
const parseJupiterRoute = async (
|
||||
jupiter: Jupiter,
|
||||
selectedRoute: RouteInfo,
|
||||
userPublicKey: PublicKey
|
||||
): Promise<TransactionInstruction[]> => {
|
||||
const { transactions } = await jupiter.exchange({
|
||||
routeInfo: selectedRoute,
|
||||
userPublicKey,
|
||||
})
|
||||
const transactions = await (
|
||||
await fetch('https://quote-api.jup.ag/v3/swap', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
// route from /quote api
|
||||
route: selectedRoute,
|
||||
// user public key to be used for the swap
|
||||
userPublicKey,
|
||||
// auto wrap and unwrap SOL. default is true
|
||||
wrapUnwrapSOL: true,
|
||||
// feeAccount is optional. Use if you want to charge a fee. feeBps must have been passed in /quote API.
|
||||
// This is the ATA account for the output token where the fee will be sent to. If you are swapping from SOL->USDC then this would be the USDC ATA you want to collect the fee.
|
||||
feeAccount: 'fee_account_public_key',
|
||||
}),
|
||||
})
|
||||
).json()
|
||||
const { swapTransaction } = transactions
|
||||
const instructions = []
|
||||
for (const ix of swapTransaction.instructions) {
|
||||
|
@ -72,7 +85,6 @@ const EMPTY_COINGECKO_PRICES = {
|
|||
const JupiterRouteInfo = ({
|
||||
amountIn,
|
||||
onClose,
|
||||
jupiter,
|
||||
routes,
|
||||
selectedRoute,
|
||||
setSelectedRoute,
|
||||
|
@ -80,15 +92,11 @@ const JupiterRouteInfo = ({
|
|||
const { t } = useTranslation(['common', 'trade'])
|
||||
const [showRoutesModal, setShowRoutesModal] = useState(false)
|
||||
const [swapRate, setSwapRate] = useState<boolean>(false)
|
||||
const [depositAndFee, setDepositAndFee] = useState<TransactionFeeInfo>()
|
||||
const [feeValue, setFeeValue] = useState<number | null>(null)
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const [coingeckoPrices, setCoingeckoPrices] = useState(EMPTY_COINGECKO_PRICES)
|
||||
const { connected } = useWallet()
|
||||
|
||||
const inputTokenInfo = mangoStore((s) => s.swap.inputTokenInfo)
|
||||
const outputTokenInfo = mangoStore((s) => s.swap.outputTokenInfo)
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const { inputTokenInfo, outputTokenInfo } = useJupiterSwapData()
|
||||
const inputBank = mangoStore((s) => s.swap.inputBank)
|
||||
|
||||
const inputTokenIconUri = useMemo(() => {
|
||||
|
@ -102,18 +110,6 @@ const JupiterRouteInfo = ({
|
|||
)
|
||||
}, [selectedRoute, outputTokenInfo])
|
||||
|
||||
useEffect(() => {
|
||||
const getDepositAndFee = async () => {
|
||||
const fees = await selectedRoute?.getDepositAndFee()
|
||||
if (fees) {
|
||||
setDepositAndFee(fees)
|
||||
}
|
||||
}
|
||||
if (selectedRoute && connected) {
|
||||
getDepositAndFee()
|
||||
}
|
||||
}, [selectedRoute, connected])
|
||||
|
||||
useEffect(() => {
|
||||
setCoingeckoPrices(EMPTY_COINGECKO_PRICES)
|
||||
const fetchTokenPrices = async () => {
|
||||
|
@ -140,7 +136,7 @@ const JupiterRouteInfo = ({
|
|||
}, [inputTokenInfo, outputTokenInfo])
|
||||
|
||||
const onSwap = async () => {
|
||||
if (!jupiter || !selectedRoute) return
|
||||
if (!selectedRoute) return
|
||||
try {
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
|
@ -151,11 +147,7 @@ const JupiterRouteInfo = ({
|
|||
|
||||
if (!mangoAccount || !group || !inputBank || !outputBank) return
|
||||
|
||||
const ixs = await parseJupiterRoute(
|
||||
jupiter,
|
||||
selectedRoute,
|
||||
mangoAccount!.owner
|
||||
)
|
||||
const ixs = await parseJupiterRoute(selectedRoute, mangoAccount!.owner)
|
||||
|
||||
try {
|
||||
setSubmitting(true)
|
||||
|
@ -201,7 +193,9 @@ const JupiterRouteInfo = ({
|
|||
|
||||
const remainingBalance =
|
||||
mangoAccount.getTokenDepositsUi(inputBank) - amountIn.toNumber()
|
||||
return remainingBalance < 0 ? Math.abs(remainingBalance) : 0
|
||||
const x = remainingBalance < 0 ? Math.abs(remainingBalance) : 0
|
||||
console.log('borrowAmount', x)
|
||||
return x
|
||||
}, [amountIn])
|
||||
|
||||
const coinGeckoPriceDifference = useMemo(() => {
|
||||
|
@ -220,6 +214,8 @@ const JupiterRouteInfo = ({
|
|||
: new Decimal(0)
|
||||
}, [coingeckoPrices, amountIn, amountOut])
|
||||
|
||||
console.log('selectedRoute', selectedRoute)
|
||||
|
||||
return routes?.length && selectedRoute && outputTokenInfo && amountOut ? (
|
||||
<div className="flex h-full flex-col justify-between">
|
||||
<div>
|
||||
|
@ -320,7 +316,7 @@ const JupiterRouteInfo = ({
|
|||
{outputTokenInfo?.decimals ? (
|
||||
<p className="text-right font-mono text-sm text-th-fgd-1">
|
||||
{formatDecimal(
|
||||
JSBI.toNumber(selectedRoute?.otherAmountThreshold) /
|
||||
selectedRoute?.otherAmountThreshold /
|
||||
10 ** outputTokenInfo.decimals || 1,
|
||||
outputTokenInfo.decimals
|
||||
)}{' '}
|
||||
|
@ -382,7 +378,7 @@ const JupiterRouteInfo = ({
|
|||
includeSeparator = true
|
||||
}
|
||||
return (
|
||||
<span key={index}>{`${info.amm.label} ${
|
||||
<span key={index}>{`${info?.label} ${
|
||||
includeSeparator ? 'x ' : ''
|
||||
}`}</span>
|
||||
)
|
||||
|
@ -402,21 +398,20 @@ const JupiterRouteInfo = ({
|
|||
</div>
|
||||
) : (
|
||||
selectedRoute?.marketInfos.map((info, index) => {
|
||||
const feeToken = jupiterTokens.find(
|
||||
const feeToken = mangoTokens.find(
|
||||
(item) => item?.address === info.lpFee?.mint
|
||||
)
|
||||
return (
|
||||
<div className="flex justify-between" key={index}>
|
||||
<p className="text-sm text-th-fgd-3">
|
||||
{t('swap:fees-paid-to', {
|
||||
route: info?.amm?.label,
|
||||
route: info?.label,
|
||||
})}
|
||||
</p>
|
||||
{feeToken?.decimals && (
|
||||
<p className="text-right font-mono text-sm text-th-fgd-1">
|
||||
{(
|
||||
JSBI.toNumber(info.lpFee?.amount) /
|
||||
Math.pow(10, feeToken.decimals)
|
||||
info.lpFee?.amount / Math.pow(10, feeToken.decimals)
|
||||
).toFixed(6)}{' '}
|
||||
<span className="font-body tracking-wide">
|
||||
{feeToken?.symbol}
|
||||
|
|
|
@ -8,10 +8,12 @@ const LeverageSlider = ({
|
|||
amount,
|
||||
leverageMax,
|
||||
onChange,
|
||||
step,
|
||||
}: {
|
||||
amount: number
|
||||
leverageMax: number
|
||||
onChange: (x: string) => any
|
||||
step: number
|
||||
}) => {
|
||||
const [value, setValue] = useState(0)
|
||||
const inputEl = useRef<HTMLInputElement>(null)
|
||||
|
@ -58,7 +60,7 @@ const LeverageSlider = ({
|
|||
type="range"
|
||||
min="0"
|
||||
max={leverageMax}
|
||||
step={inputTokenInfo ? 1 / 10 ** inputTokenInfo?.decimals : 6}
|
||||
step={step}
|
||||
className="w-full"
|
||||
onChange={handleSliderChange}
|
||||
value={value}
|
||||
|
@ -71,10 +73,12 @@ export const SwapLeverageSlider = ({
|
|||
amount,
|
||||
onChange,
|
||||
useMargin,
|
||||
step,
|
||||
}: {
|
||||
amount: number
|
||||
onChange: (x: string) => void
|
||||
useMargin: boolean
|
||||
step: number
|
||||
}) => {
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const { amountWithBorrow } = useTokenMax(useMargin)
|
||||
|
@ -82,12 +86,18 @@ export const SwapLeverageSlider = ({
|
|||
return (
|
||||
<>
|
||||
{!mangoAccount ? (
|
||||
<LeverageSlider amount={amount} leverageMax={100} onChange={onChange} />
|
||||
<LeverageSlider
|
||||
amount={amount}
|
||||
leverageMax={100}
|
||||
onChange={onChange}
|
||||
step={step}
|
||||
/>
|
||||
) : (
|
||||
<LeverageSlider
|
||||
amount={amount}
|
||||
leverageMax={amountWithBorrow.toNumber()}
|
||||
onChange={onChange}
|
||||
step={step}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import { RouteInfo } from '@jup-ag/core'
|
||||
import { Dispatch, SetStateAction } from 'react'
|
||||
import JSBI from 'jsbi'
|
||||
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { Token } from '../../types/jupiter'
|
||||
import { RouteInfo, Token } from '../../types/jupiter'
|
||||
import { formatDecimal } from '../../utils/numbers'
|
||||
import Modal from '../shared/Modal'
|
||||
import useJupiterMints from '../../hooks/useJupiterMints'
|
||||
|
||||
type RoutesModalProps = {
|
||||
onClose: () => void
|
||||
|
@ -26,7 +24,7 @@ const RoutesModal = ({
|
|||
inputTokenSymbol,
|
||||
outputTokenInfo,
|
||||
}: RoutesModalProps) => {
|
||||
const tokens = mangoStore.getState().jupiterTokens
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
|
||||
const handleSelectRoute = (route: RouteInfo) => {
|
||||
setSelectedRoute(route)
|
||||
|
@ -40,7 +38,7 @@ const RoutesModal = ({
|
|||
</div>
|
||||
<div className="thin-scroll max-h-96 overflow-y-auto overflow-x-hidden">
|
||||
{routes?.map((route, index) => {
|
||||
const selected = selectedRoute === route
|
||||
const selected = selectedRoute.outAmount === route.outAmount
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
|
@ -66,7 +64,7 @@ const RoutesModal = ({
|
|||
includeSeparator = true
|
||||
}
|
||||
return (
|
||||
<span key={index}>{`${info.amm.label} ${
|
||||
<span key={index}>{`${info.label} ${
|
||||
includeSeparator ? 'x ' : ''
|
||||
}`}</span>
|
||||
)
|
||||
|
@ -81,7 +79,7 @@ const RoutesModal = ({
|
|||
<span key={index}>
|
||||
<span>
|
||||
{
|
||||
tokens.find(
|
||||
mangoTokens.find(
|
||||
(item) =>
|
||||
item?.address === r?.outputMint?.toString()
|
||||
)?.symbol
|
||||
|
@ -95,8 +93,7 @@ const RoutesModal = ({
|
|||
</div>
|
||||
<div className="text-lg">
|
||||
{formatDecimal(
|
||||
JSBI.toNumber(route.outAmount) /
|
||||
10 ** (outputTokenInfo?.decimals || 1),
|
||||
route.outAmount / 10 ** (outputTokenInfo?.decimals || 1),
|
||||
6
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
ExclamationCircleIcon,
|
||||
LinkIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import { RouteInfo } from '@jup-ag/core'
|
||||
import NumberFormat, { NumberFormatValues } from 'react-number-format'
|
||||
import Decimal from 'decimal.js'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
|
@ -24,19 +23,22 @@ import Button, { IconButton } from '../shared/Button'
|
|||
import ButtonGroup from '../forms/ButtonGroup'
|
||||
import Loading from '../shared/Loading'
|
||||
import { EnterBottomExitBottom } from '../shared/Transitions'
|
||||
import useJupiter from './useJupiter'
|
||||
import useJupiterRoutes from './useJupiterRoutes'
|
||||
import SwapSettings from './SwapSettings'
|
||||
import SheenLoader from '../shared/SheenLoader'
|
||||
import { HealthType } from '@blockworks-foundation/mango-v4'
|
||||
import {
|
||||
INPUT_TOKEN_DEFAULT,
|
||||
MANGO_MINT,
|
||||
OUTPUT_TOKEN_DEFAULT,
|
||||
USDC_MINT,
|
||||
} from '../../utils/constants'
|
||||
import { useTokenMax } from './useTokenMax'
|
||||
import MaxAmountButton from '@components/shared/MaxAmountButton'
|
||||
import HealthImpact from '@components/shared/HealthImpact'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import { RouteInfo } from 'types/jupiter'
|
||||
|
||||
const MAX_DIGITS = 11
|
||||
export const withValueLimit = (values: NumberFormatValues): boolean => {
|
||||
|
@ -53,15 +55,15 @@ const SwapForm = () => {
|
|||
const [showTokenSelect, setShowTokenSelect] = useState('')
|
||||
const [showSettings, setShowSettings] = useState(false)
|
||||
const [showConfirm, setShowConfirm] = useState(false)
|
||||
|
||||
const group = mangoStore.getState().group
|
||||
console.log('amountInFormValue', amountInFormValue)
|
||||
|
||||
const set = mangoStore.getState().set
|
||||
const useMargin = mangoStore((s) => s.swap.margin)
|
||||
const slippage = mangoStore((s) => s.swap.slippage)
|
||||
const inputTokenInfo = mangoStore((s) => s.swap.inputTokenInfo)
|
||||
const outputTokenInfo = mangoStore((s) => s.swap.outputTokenInfo)
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const {
|
||||
margin: useMargin,
|
||||
slippage,
|
||||
inputBank,
|
||||
outputBank,
|
||||
} = mangoStore((s) => s.swap)
|
||||
const [debouncedAmountIn] = useDebounce(amountInFormValue, 300)
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const { connected } = useWallet()
|
||||
|
@ -72,16 +74,26 @@ const SwapForm = () => {
|
|||
: new Decimal(0)
|
||||
}, [debouncedAmountIn])
|
||||
|
||||
const { amountOut, jupiter, routes } = useJupiter({
|
||||
inputTokenInfo,
|
||||
outputTokenInfo,
|
||||
const { bestRoute, routes } = useJupiterRoutes({
|
||||
inputMint: inputBank?.mint.toString() || USDC_MINT,
|
||||
outputMint: outputBank?.mint.toString() || MANGO_MINT,
|
||||
inputAmount: debouncedAmountIn,
|
||||
slippage,
|
||||
})
|
||||
|
||||
const outAmount: number = useMemo(() => {
|
||||
return selectedRoute?.outAmount.toString()
|
||||
? new Decimal(selectedRoute.outAmount.toString())
|
||||
.div(10 ** outputBank!.mintDecimals)
|
||||
.toNumber()
|
||||
: 0
|
||||
}, [selectedRoute, outputBank])
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedRoute(routes[0])
|
||||
}, [routes])
|
||||
if (bestRoute) {
|
||||
setSelectedRoute(bestRoute)
|
||||
}
|
||||
}, [bestRoute])
|
||||
|
||||
useEffect(() => {
|
||||
setAmountInFormValue('')
|
||||
|
@ -93,71 +105,50 @@ const SwapForm = () => {
|
|||
|
||||
const handleTokenInSelect = useCallback(
|
||||
(mintAddress: string) => {
|
||||
const inputTokenInfo = jupiterTokens.find(
|
||||
(t: any) => t.address === mintAddress
|
||||
)
|
||||
const group = mangoStore.getState().group
|
||||
if (group) {
|
||||
const bank = group.getFirstBankByMint(new PublicKey(mintAddress))
|
||||
set((s) => {
|
||||
s.swap.inputBank = bank
|
||||
s.swap.inputTokenInfo = inputTokenInfo
|
||||
})
|
||||
}
|
||||
setShowTokenSelect('')
|
||||
},
|
||||
[jupiterTokens, set]
|
||||
[set]
|
||||
)
|
||||
|
||||
const handleTokenOutSelect = useCallback(
|
||||
(mintAddress: string) => {
|
||||
const outputTokenInfo = jupiterTokens.find(
|
||||
(t: any) => t.address === mintAddress
|
||||
)
|
||||
const group = mangoStore.getState().group
|
||||
if (group) {
|
||||
const bank = group.getFirstBankByMint(new PublicKey(mintAddress))
|
||||
set((s) => {
|
||||
s.swap.outputBank = bank
|
||||
s.swap.outputTokenInfo = outputTokenInfo
|
||||
})
|
||||
}
|
||||
setShowTokenSelect('')
|
||||
},
|
||||
[jupiterTokens, set]
|
||||
[set]
|
||||
)
|
||||
|
||||
const handleSwitchTokens = useCallback(() => {
|
||||
if (amountIn?.gt(0)) {
|
||||
setAmountInFormValue(amountOut.toString())
|
||||
if (amountIn?.gt(0) && outAmount) {
|
||||
setAmountInFormValue(outAmount.toString())
|
||||
}
|
||||
const inputBank = mangoStore.getState().swap.inputBank
|
||||
const outputBank = mangoStore.getState().swap.outputBank
|
||||
set((s) => {
|
||||
s.swap.inputBank = outputBank
|
||||
s.swap.outputBank = inputBank
|
||||
s.swap.inputTokenInfo = outputTokenInfo
|
||||
s.swap.outputTokenInfo = inputTokenInfo
|
||||
})
|
||||
setAnimateSwitchArrow(
|
||||
(prevanimateSwitchArrow) => prevanimateSwitchArrow + 1
|
||||
)
|
||||
}, [inputTokenInfo, outputTokenInfo, set, amountOut, amountIn])
|
||||
|
||||
const currentMaintHealth = useMemo(() => {
|
||||
if (!group || !mangoAccount) return 0
|
||||
return mangoAccount.getHealthRatioUi(group, HealthType.maint)
|
||||
}, [mangoAccount])
|
||||
}, [set, outAmount, amountIn])
|
||||
|
||||
const maintProjectedHealth = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
if (
|
||||
!inputTokenInfo ||
|
||||
!mangoAccount ||
|
||||
!outputTokenInfo ||
|
||||
!amountOut ||
|
||||
!group
|
||||
)
|
||||
if (!inputBank || !mangoAccount || !outputBank || !outAmount || !group)
|
||||
return 0
|
||||
|
||||
const simulatedHealthRatio =
|
||||
|
@ -165,12 +156,12 @@ const SwapForm = () => {
|
|||
group,
|
||||
[
|
||||
{
|
||||
mintPk: new PublicKey(inputTokenInfo.address),
|
||||
mintPk: inputBank.mint,
|
||||
uiTokenAmount: amountIn.toNumber() * -1,
|
||||
},
|
||||
{
|
||||
mintPk: new PublicKey(outputTokenInfo.address),
|
||||
uiTokenAmount: amountOut.toNumber(),
|
||||
mintPk: outputBank.mint,
|
||||
uiTokenAmount: outAmount,
|
||||
},
|
||||
],
|
||||
HealthType.maint
|
||||
|
@ -180,15 +171,11 @@ const SwapForm = () => {
|
|||
: simulatedHealthRatio! < 0
|
||||
? 0
|
||||
: Math.trunc(simulatedHealthRatio!)
|
||||
}, [mangoAccount, inputTokenInfo, outputTokenInfo, amountIn, amountOut])
|
||||
}, [mangoAccount, inputBank, outputBank, amountIn, outAmount])
|
||||
|
||||
const loadingSwapDetails: boolean = useMemo(() => {
|
||||
return (
|
||||
!!amountIn.toNumber() && connected && (!selectedRoute || !outputTokenInfo)
|
||||
)
|
||||
}, [amountIn, connected, selectedRoute, outputTokenInfo])
|
||||
|
||||
const showHealthImpact = !!inputTokenInfo && !!outputTokenInfo && !!amountOut
|
||||
return !!amountIn.toNumber() && connected && !selectedRoute
|
||||
}, [amountIn, connected, selectedRoute])
|
||||
|
||||
return (
|
||||
<ContentBox
|
||||
|
@ -211,7 +198,6 @@ const SwapForm = () => {
|
|||
onClose={() => setShowConfirm(false)}
|
||||
amountIn={amountIn}
|
||||
slippage={slippage}
|
||||
jupiter={jupiter}
|
||||
routes={routes}
|
||||
selectedRoute={selectedRoute}
|
||||
setSelectedRoute={setSelectedRoute}
|
||||
|
@ -260,7 +246,7 @@ const SwapForm = () => {
|
|||
<div className="mb-3 grid grid-cols-2" id="swap-step-two">
|
||||
<div className="col-span-1 rounded-lg rounded-r-none border border-r-0 border-th-bkg-4 bg-th-bkg-1">
|
||||
<TokenSelect
|
||||
tokenSymbol={inputTokenInfo?.symbol || INPUT_TOKEN_DEFAULT}
|
||||
tokenSymbol={inputBank?.name || INPUT_TOKEN_DEFAULT}
|
||||
showTokenList={setShowTokenSelect}
|
||||
type="input"
|
||||
/>
|
||||
|
@ -271,7 +257,7 @@ const SwapForm = () => {
|
|||
thousandSeparator=","
|
||||
allowNegative={false}
|
||||
isNumericString={true}
|
||||
decimalScale={inputTokenInfo?.decimals || 6}
|
||||
decimalScale={inputBank?.mintDecimals || 6}
|
||||
name="amountIn"
|
||||
id="amountIn"
|
||||
className="w-full rounded-r-lg border border-th-bkg-4 bg-th-bkg-1 p-3 text-right font-mono text-base font-bold text-th-fgd-1 focus:outline-none lg:text-lg xl:text-xl"
|
||||
|
@ -308,7 +294,7 @@ const SwapForm = () => {
|
|||
<div id="swap-step-three" className="mb-3 grid grid-cols-2">
|
||||
<div className="col-span-1 rounded-lg rounded-r-none border border-r-0 border-th-bkg-4 bg-th-bkg-1">
|
||||
<TokenSelect
|
||||
tokenSymbol={outputTokenInfo?.symbol || OUTPUT_TOKEN_DEFAULT}
|
||||
tokenSymbol={outputBank?.name || OUTPUT_TOKEN_DEFAULT}
|
||||
showTokenList={setShowTokenSelect}
|
||||
type="output"
|
||||
/>
|
||||
|
@ -329,15 +315,13 @@ const SwapForm = () => {
|
|||
thousandSeparator=","
|
||||
allowNegative={false}
|
||||
isNumericString={true}
|
||||
decimalScale={outputTokenInfo?.decimals || 6}
|
||||
decimalScale={outputBank?.mintDecimals || 6}
|
||||
name="amountOut"
|
||||
id="amountOut"
|
||||
className="w-full rounded-r-lg bg-th-bkg-3 p-3 text-right font-mono text-base font-bold text-th-fgd-3 focus:outline-none lg:text-lg xl:text-xl"
|
||||
placeholder="0.00"
|
||||
disabled
|
||||
value={
|
||||
amountOut ? numberFormat.format(amountOut.toNumber()) : ''
|
||||
}
|
||||
value={outAmount ? numberFormat.format(outAmount) : ''}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
@ -352,6 +336,7 @@ const SwapForm = () => {
|
|||
useMargin={useMargin}
|
||||
amount={amountIn.toNumber()}
|
||||
onChange={setAmountInFormValue}
|
||||
step={1 / 10 ** (inputBank?.mintDecimals || 6)}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
|
@ -360,8 +345,8 @@ const SwapForm = () => {
|
|||
useMargin={useMargin}
|
||||
setShowConfirm={setShowConfirm}
|
||||
amountIn={amountIn}
|
||||
inputSymbol={inputTokenInfo?.symbol}
|
||||
amountOut={amountOut}
|
||||
inputSymbol={inputBank?.name}
|
||||
amountOut={selectedRoute ? outAmount : undefined}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
|
@ -385,7 +370,7 @@ const SwapFormSubmitButton = ({
|
|||
useMargin,
|
||||
}: {
|
||||
amountIn: Decimal
|
||||
amountOut: Decimal
|
||||
amountOut: number | undefined
|
||||
inputSymbol: string | undefined
|
||||
loadingSwapDetails: boolean
|
||||
setShowConfirm: (x: any) => any
|
||||
|
@ -400,10 +385,7 @@ const SwapFormSubmitButton = ({
|
|||
: tokenMax.lt(amountIn)
|
||||
|
||||
const disabled =
|
||||
!amountIn.toNumber() ||
|
||||
!connected ||
|
||||
showInsufficientBalance ||
|
||||
!amountOut.gt(0)
|
||||
!amountIn.toNumber() || !connected || showInsufficientBalance || !amountOut
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
import { memo, useMemo, useState, useEffect, ChangeEvent } from 'react'
|
||||
import Image from 'next/legacy/image'
|
||||
import { memo, useMemo, useEffect } from 'react'
|
||||
import { Token } from '../../types/jupiter'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import Input from '../forms/Input'
|
||||
import { IconButton } from '../shared/Button'
|
||||
import {
|
||||
QuestionMarkCircleIcon,
|
||||
MagnifyingGlassIcon,
|
||||
XMarkIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import { XMarkIcon } from '@heroicons/react/20/solid'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { floorToDecimal } from '../../utils/numbers'
|
||||
import Decimal from 'decimal.js'
|
||||
import { getTokenInMax } from './useTokenMax'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
|
||||
const generateSearchTerm = (item: Token, searchValue: string) => {
|
||||
const normalizedSearchValue = searchValue.toLowerCase()
|
||||
|
@ -99,10 +93,8 @@ const SwapFormTokenList = ({
|
|||
useMargin: boolean
|
||||
}) => {
|
||||
const { t } = useTranslation(['common', 'swap'])
|
||||
const [search, setSearch] = useState('')
|
||||
const tokens = mangoStore.getState().jupiterTokens
|
||||
const walletTokens = mangoStore((s) => s.wallet.tokens)
|
||||
// const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
// const [search, setSearch] = useState('')
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const inputBank = mangoStore((s) => s.swap.inputBank)
|
||||
const outputBank = mangoStore((s) => s.swap.outputBank)
|
||||
const group = mangoStore((s) => s.group)
|
||||
|
@ -128,13 +120,13 @@ const SwapFormTokenList = ({
|
|||
|
||||
const tokenInfos = useMemo(() => {
|
||||
if (
|
||||
tokens?.length &&
|
||||
mangoTokens?.length &&
|
||||
group &&
|
||||
mangoAccount &&
|
||||
outputBank &&
|
||||
type === 'input'
|
||||
) {
|
||||
const filteredSortedTokens = tokens
|
||||
const filteredSortedTokens = mangoTokens
|
||||
.map((token) => {
|
||||
const max = getTokenInMax(
|
||||
mangoAccount,
|
||||
|
@ -152,8 +144,8 @@ const SwapFormTokenList = ({
|
|||
)
|
||||
|
||||
return filteredSortedTokens
|
||||
} else if (tokens?.length) {
|
||||
const filteredTokens = tokens
|
||||
} else if (mangoTokens?.length) {
|
||||
const filteredTokens = mangoTokens
|
||||
.map((token) => ({
|
||||
...token,
|
||||
amount: new Decimal(0),
|
||||
|
@ -164,7 +156,7 @@ const SwapFormTokenList = ({
|
|||
} else {
|
||||
return []
|
||||
}
|
||||
}, [tokens, walletTokens, inputBank, outputBank, mangoAccount, group])
|
||||
}, [mangoTokens, inputBank, outputBank, mangoAccount, group, useMargin, type])
|
||||
|
||||
// const handleUpdateSearch = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
// setSearch(e.target.value)
|
||||
|
@ -203,8 +195,8 @@ const SwapFormTokenList = ({
|
|||
<div className="mt-4 flex flex-wrap">
|
||||
{popularTokens.map((token) => {
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
if (mangoTokens.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === token.address
|
||||
)!.logoURI
|
||||
}
|
||||
|
|
|
@ -13,8 +13,7 @@ import { useViewport } from '../../hooks/useViewport'
|
|||
import { IconButton } from '../shared/Button'
|
||||
import { Transition } from '@headlessui/react'
|
||||
import SheenLoader from '../shared/SheenLoader'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import mangoStore, { SwapHistoryItem } from '@store/mangoStore'
|
||||
import { SwapHistoryItem } from '@store/mangoStore'
|
||||
import {
|
||||
countLeadingZeros,
|
||||
formatFixedDecimals,
|
||||
|
@ -26,6 +25,7 @@ import { EXPLORERS } from 'pages/settings'
|
|||
import Tooltip from '@components/shared/Tooltip'
|
||||
import { formatTokenSymbol } from 'utils/tokens'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
|
||||
const SwapHistoryTable = ({
|
||||
swapHistory,
|
||||
|
@ -35,7 +35,7 @@ const SwapHistoryTable = ({
|
|||
loading: boolean
|
||||
}) => {
|
||||
const { t } = useTranslation(['common', 'settings'])
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const [showSwapDetails, setSwapDetails] = useState('')
|
||||
const { width } = useViewport()
|
||||
|
@ -95,11 +95,11 @@ const SwapHistoryTable = ({
|
|||
const inSymbol = formatTokenSymbol(swap_in_symbol)
|
||||
const outSymbol = formatTokenSymbol(swap_out_symbol)
|
||||
|
||||
if (jupiterTokens.length) {
|
||||
baseLogoURI = jupiterTokens.find(
|
||||
if (mangoTokens.length) {
|
||||
baseLogoURI = mangoTokens.find(
|
||||
(t) => t.symbol === inSymbol
|
||||
)?.logoURI
|
||||
quoteLogoURI = jupiterTokens.find(
|
||||
quoteLogoURI = mangoTokens.find(
|
||||
(t) => t.symbol === outSymbol
|
||||
)?.logoURI
|
||||
}
|
||||
|
@ -255,11 +255,11 @@ const SwapHistoryTable = ({
|
|||
const inSymbol = formatTokenSymbol(swap_in_symbol)
|
||||
const outSymbol = formatTokenSymbol(swap_out_symbol)
|
||||
|
||||
if (jupiterTokens.length) {
|
||||
baseLogoURI = jupiterTokens.find(
|
||||
if (mangoTokens.length) {
|
||||
baseLogoURI = mangoTokens.find(
|
||||
(t) => t.symbol === inSymbol
|
||||
)?.logoURI
|
||||
quoteLogoURI = jupiterTokens.find(
|
||||
quoteLogoURI = mangoTokens.find(
|
||||
(t) => t.symbol === outSymbol
|
||||
)?.logoURI
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@ import { IS_ONBOARDED_KEY } from 'utils/constants'
|
|||
const SwapTokenChart = dynamic(() => import('./SwapTokenChart'), { ssr: false })
|
||||
|
||||
const SwapPage = () => {
|
||||
const inputTokenInfo = mangoStore((s) => s.swap.inputTokenInfo)
|
||||
const outputTokenInfo = mangoStore((s) => s.swap.outputTokenInfo)
|
||||
const { connected } = useWallet()
|
||||
const tourSettings = mangoStore((s) => s.settings.tours)
|
||||
const [isOnboarded] = useLocalStorageState(IS_ONBOARDED_KEY)
|
||||
|
@ -19,13 +17,7 @@ const SwapPage = () => {
|
|||
<>
|
||||
<div className="grid grid-cols-12">
|
||||
<div className="col-span-12 border-th-bkg-3 md:col-span-6 md:border-b lg:col-span-7 xl:col-span-8">
|
||||
{inputTokenInfo?.extensions?.coingeckoId &&
|
||||
outputTokenInfo?.extensions?.coingeckoId ? (
|
||||
<SwapTokenChart
|
||||
inputTokenId={inputTokenInfo?.extensions?.coingeckoId}
|
||||
outputTokenId={outputTokenInfo?.extensions?.coingeckoId}
|
||||
/>
|
||||
) : null}
|
||||
<SwapTokenChart />
|
||||
</div>
|
||||
<div className="col-span-12 mt-2 space-y-6 border-th-bkg-3 md:col-span-6 md:mt-0 md:border-b lg:col-span-5 xl:col-span-4">
|
||||
<SwapForm />
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
import {
|
||||
FunctionComponent,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import {
|
||||
|
@ -31,14 +25,10 @@ import { formatTokenSymbol } from 'utils/tokens'
|
|||
import { useQuery } from '@tanstack/react-query'
|
||||
import { fetchChartData } from 'apis/coingecko'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import useJupiterSwapData from './useJupiterSwapData'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
interface SwapTokenChartProps {
|
||||
inputTokenId: string
|
||||
outputTokenId: string
|
||||
}
|
||||
|
||||
const CustomizedLabel = ({
|
||||
chartData,
|
||||
x,
|
||||
|
@ -77,21 +67,19 @@ const CustomizedLabel = ({
|
|||
} else return <div />
|
||||
}
|
||||
|
||||
const SwapTokenChart: FunctionComponent<SwapTokenChartProps> = ({
|
||||
inputTokenId,
|
||||
outputTokenId,
|
||||
}) => {
|
||||
const inputBank = mangoStore((s) => s.swap.inputBank)
|
||||
const outputBank = mangoStore((s) => s.swap.outputBank)
|
||||
const [baseTokenId, setBaseTokenId] = useState(inputTokenId)
|
||||
const [quoteTokenId, setQuoteTokenId] = useState(outputTokenId)
|
||||
const SwapTokenChart = () => {
|
||||
const { inputBank, outputBank } = mangoStore((s) => s.swap)
|
||||
const { inputCoingeckoId, outputCoingeckoId } = useJupiterSwapData()
|
||||
const [baseTokenId, setBaseTokenId] = useState(inputCoingeckoId)
|
||||
const [quoteTokenId, setQuoteTokenId] = useState(outputCoingeckoId)
|
||||
const [mouseData, setMouseData] = useState<any>(null)
|
||||
const [daysToShow, setDaysToShow] = useState(1)
|
||||
const { theme } = useTheme()
|
||||
|
||||
const chartDataQuery = useQuery(
|
||||
['chart-data', baseTokenId, quoteTokenId, daysToShow],
|
||||
() => fetchChartData(baseTokenId, quoteTokenId, daysToShow),
|
||||
{ staleTime: 0 }
|
||||
{ staleTime: 0, enabled: !!baseTokenId && !!quoteTokenId }
|
||||
)
|
||||
const chartData = chartDataQuery.data
|
||||
|
||||
|
@ -106,16 +94,16 @@ const SwapTokenChart: FunctionComponent<SwapTokenChartProps> = ({
|
|||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!inputTokenId || !outputTokenId) return
|
||||
if (!inputCoingeckoId || !outputCoingeckoId) return
|
||||
|
||||
if (['usd-coin', 'tether'].includes(outputTokenId)) {
|
||||
setBaseTokenId(inputTokenId)
|
||||
setQuoteTokenId(outputTokenId)
|
||||
if (['usd-coin', 'tether'].includes(outputCoingeckoId)) {
|
||||
setBaseTokenId(inputCoingeckoId)
|
||||
setQuoteTokenId(outputCoingeckoId)
|
||||
} else {
|
||||
setBaseTokenId(outputTokenId)
|
||||
setQuoteTokenId(inputTokenId)
|
||||
setBaseTokenId(outputCoingeckoId)
|
||||
setQuoteTokenId(inputCoingeckoId)
|
||||
}
|
||||
}, [inputTokenId, outputTokenId])
|
||||
}, [inputCoingeckoId, outputCoingeckoId])
|
||||
|
||||
// const handleFlipChart = useCallback(() => {
|
||||
// if (!baseTokenId || !quoteTokenId) return
|
||||
|
@ -144,7 +132,7 @@ const SwapTokenChart: FunctionComponent<SwapTokenChartProps> = ({
|
|||
|
||||
return (
|
||||
<ContentBox hideBorder hidePadding className="h-full px-6 py-3">
|
||||
{chartDataQuery?.isLoading ? (
|
||||
{chartDataQuery?.isLoading || chartDataQuery.isFetching ? (
|
||||
<>
|
||||
<SheenLoader className="w-[148px] rounded-md">
|
||||
<div className="h-[18px] bg-th-bkg-2" />
|
||||
|
@ -159,14 +147,14 @@ const SwapTokenChart: FunctionComponent<SwapTokenChartProps> = ({
|
|||
<div className="h-[308px] bg-th-bkg-2" />
|
||||
</SheenLoader>
|
||||
</>
|
||||
) : chartData.length && baseTokenId && quoteTokenId ? (
|
||||
) : chartData?.length && baseTokenId && quoteTokenId ? (
|
||||
<div className="relative">
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
{inputBank && outputBank ? (
|
||||
<div className="mb-0.5 flex items-center">
|
||||
<p className="text-base text-th-fgd-3">
|
||||
{['usd-coin', 'tether'].includes(inputTokenId || '')
|
||||
{['usd-coin', 'tether'].includes(inputCoingeckoId || '')
|
||||
? `${formatTokenSymbol(
|
||||
outputBank?.name?.toUpperCase()
|
||||
)}/${inputBank?.name?.toUpperCase()}`
|
||||
|
|
|
@ -3,7 +3,8 @@ import {
|
|||
QuestionMarkCircleIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import Image from 'next/legacy/image'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
|
||||
type TokenSelectProps = {
|
||||
tokenSymbol: string | undefined
|
||||
|
@ -16,14 +17,14 @@ const TokenSelect = ({
|
|||
showTokenList,
|
||||
type,
|
||||
}: TokenSelectProps) => {
|
||||
const group = mangoStore((s) => s.group)
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { group } = useMangoGroup()
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
|
||||
if (!group) return null
|
||||
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find((t) => t.symbol === tokenSymbol)!.logoURI
|
||||
if (mangoTokens.length) {
|
||||
logoURI = mangoTokens.find((t) => t.symbol === tokenSymbol)!.logoURI
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
import { toUiDecimals } from '@blockworks-foundation/mango-v4'
|
||||
import { Jupiter, RouteInfo } from '@jup-ag/core'
|
||||
import { useEffect, useState } from 'react'
|
||||
import JSBI from 'jsbi'
|
||||
import Decimal from 'decimal.js'
|
||||
|
||||
import mangoStore, { CLUSTER } from '@store/mangoStore'
|
||||
import { Token } from '../../types/jupiter'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
|
||||
type useJupiterPropTypes = {
|
||||
inputTokenInfo: Token | undefined
|
||||
outputTokenInfo: Token | undefined
|
||||
inputAmount: string
|
||||
slippage: number
|
||||
}
|
||||
|
||||
type RouteParams = {
|
||||
routes: RouteInfo[]
|
||||
amountOut: Decimal
|
||||
}
|
||||
|
||||
const defaultComputedInfo = {
|
||||
routes: [],
|
||||
amountOut: new Decimal(0),
|
||||
}
|
||||
|
||||
const useJupiter = ({
|
||||
inputTokenInfo,
|
||||
outputTokenInfo,
|
||||
inputAmount,
|
||||
slippage,
|
||||
}: useJupiterPropTypes) => {
|
||||
const [jupiter, setJupiter] = useState<Jupiter>()
|
||||
const [computedInfo, setComputedInfo] =
|
||||
useState<RouteParams>(defaultComputedInfo)
|
||||
|
||||
useEffect(() => {
|
||||
const connection = mangoStore.getState().connection
|
||||
const loadJupiter = async () => {
|
||||
const jupiter = await Jupiter.load({
|
||||
connection,
|
||||
cluster: CLUSTER,
|
||||
wrapUnwrapSOL: false,
|
||||
// platformFeeAndAccounts: NO_PLATFORM_FEE,
|
||||
routeCacheDuration: 30_000, // Will not refetch data on computeRoutes for up to 10 seconds
|
||||
})
|
||||
setJupiter(jupiter)
|
||||
}
|
||||
try {
|
||||
loadJupiter()
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const group = mangoStore.getState().group
|
||||
if (!group) return
|
||||
const tokens = mangoStore.getState().jupiterTokens
|
||||
|
||||
const loadRoutes = async () => {
|
||||
if (!outputTokenInfo || !inputTokenInfo) return
|
||||
if (!inputAmount) {
|
||||
setComputedInfo(defaultComputedInfo)
|
||||
} else {
|
||||
try {
|
||||
const computedRoutes = await jupiter
|
||||
?.computeRoutes({
|
||||
inputMint: new PublicKey(inputTokenInfo.address), // Mint address of the input token
|
||||
outputMint: new PublicKey(outputTokenInfo.address), // Mint address of the output token
|
||||
amount: JSBI.BigInt(
|
||||
new Decimal(inputAmount).mul(10 ** inputTokenInfo.decimals)
|
||||
),
|
||||
slippage, // The slippage in % terms
|
||||
filterTopNResult: 10,
|
||||
onlyDirectRoutes: true,
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Error computing Jupiter routes:', e)
|
||||
return
|
||||
})
|
||||
|
||||
const routesInfosWithoutRaydium = computedRoutes?.routesInfos.filter(
|
||||
(r) => {
|
||||
for (const mkt of r.marketInfos) {
|
||||
if (mkt.amm.label === 'Raydium' || mkt.amm.label === 'Serum')
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
)
|
||||
if (routesInfosWithoutRaydium?.length) {
|
||||
const bestRoute = routesInfosWithoutRaydium[0]
|
||||
|
||||
setComputedInfo({
|
||||
routes: routesInfosWithoutRaydium,
|
||||
amountOut: new Decimal(bestRoute.outAmount.toString()).div(
|
||||
10 ** outputTokenInfo.decimals!
|
||||
),
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadRoutes()
|
||||
}, [inputTokenInfo, outputTokenInfo, jupiter, slippage, inputAmount])
|
||||
|
||||
return { jupiter, ...computedInfo }
|
||||
}
|
||||
|
||||
export default useJupiter
|
|
@ -0,0 +1,81 @@
|
|||
import { useQuery } from '@tanstack/react-query'
|
||||
import Decimal from 'decimal.js'
|
||||
import { RouteInfo } from 'types/jupiter'
|
||||
import useJupiterSwapData from './useJupiterSwapData'
|
||||
|
||||
type useJupiterPropTypes = {
|
||||
inputMint: string
|
||||
outputMint: string
|
||||
inputAmount: string
|
||||
slippage: number
|
||||
}
|
||||
|
||||
const fetchJupiterRoutes = async (
|
||||
inputMint: string = 'So11111111111111111111111111111111111111112',
|
||||
outputMint: string = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
||||
amount: number = 0,
|
||||
slippageBps: number = 50,
|
||||
feeBps: number = 0
|
||||
) => {
|
||||
{
|
||||
const params: any = {
|
||||
inputMint: inputMint.toString(),
|
||||
outputMint: outputMint.toString(),
|
||||
amount,
|
||||
slippageBps,
|
||||
onlyDirectRoutes: 'true',
|
||||
feeBps,
|
||||
}
|
||||
|
||||
const paramsString = new URLSearchParams(params).toString()
|
||||
const response = await fetch(
|
||||
`https://quote-api.jup.ag/v1/quote?${paramsString}`
|
||||
)
|
||||
|
||||
const res = await response.json()
|
||||
const data = res.data
|
||||
|
||||
return {
|
||||
routes: res.data,
|
||||
bestRoute: data[0],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const useJupiterRoutes = ({
|
||||
inputMint,
|
||||
outputMint,
|
||||
inputAmount,
|
||||
slippage,
|
||||
}: useJupiterPropTypes) => {
|
||||
const { inputTokenInfo } = useJupiterSwapData()
|
||||
|
||||
const amount = inputAmount
|
||||
? new Decimal(inputAmount).mul(10 ** (inputTokenInfo?.decimals || 6))
|
||||
: new Decimal(0)
|
||||
|
||||
const res = useQuery<{ routes: RouteInfo[]; bestRoute: RouteInfo }, Error>(
|
||||
['swap-routes', inputMint, outputMint, inputAmount, slippage],
|
||||
async () =>
|
||||
fetchJupiterRoutes(inputMint, outputMint, amount.toNumber(), slippage),
|
||||
{
|
||||
enabled: inputAmount ? true : false,
|
||||
}
|
||||
)
|
||||
|
||||
return inputAmount
|
||||
? {
|
||||
...(res.data ?? {
|
||||
routes: [],
|
||||
bestRoute: undefined,
|
||||
}),
|
||||
isLoading: res.isLoading,
|
||||
}
|
||||
: {
|
||||
routes: [],
|
||||
bestRoute: undefined,
|
||||
isLoading: false,
|
||||
}
|
||||
}
|
||||
|
||||
export default useJupiterRoutes
|
|
@ -0,0 +1,33 @@
|
|||
import { useMemo } from 'react'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
|
||||
const useJupiterSwapData = () => {
|
||||
const inputBank = mangoStore((s) => s.swap.inputBank)
|
||||
const outputBank = mangoStore((s) => s.swap.outputBank)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
|
||||
const [inputTokenInfo, outputTokenInfo] = useMemo(() => {
|
||||
if (inputBank && outputBank) {
|
||||
return [
|
||||
mangoTokens?.find(
|
||||
(item) => item?.address === inputBank.mint.toString() || ''
|
||||
),
|
||||
mangoTokens?.find(
|
||||
(item) => item?.address === outputBank.mint.toString() || ''
|
||||
),
|
||||
]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}, [inputBank, outputBank, mangoTokens])
|
||||
|
||||
return {
|
||||
inputTokenInfo,
|
||||
inputCoingeckoId: inputTokenInfo?.extensions?.coingeckoId,
|
||||
outputTokenInfo,
|
||||
outputCoingeckoId: outputTokenInfo?.extensions?.coingeckoId,
|
||||
}
|
||||
}
|
||||
|
||||
export default useJupiterSwapData
|
|
@ -4,6 +4,7 @@ import TabUnderline from '@components/shared/TabUnderline'
|
|||
import { Popover } from '@headlessui/react'
|
||||
import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useCoingecko } from 'hooks/useCoingecko'
|
||||
import useOraclePrice from 'hooks/useOraclePrice'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
|
@ -113,16 +114,14 @@ const MarketSelectDropdown = () => {
|
|||
const AdvancedMarketHeader = () => {
|
||||
const { t } = useTranslation(['common', 'trade'])
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data)
|
||||
const actions = mangoStore((s) => s.actions)
|
||||
const serumMarkets = mangoStore((s) => s.serumMarkets)
|
||||
const { data: tokenPrices } = useCoingecko()
|
||||
const oraclePrice = useOraclePrice()
|
||||
|
||||
const baseSymbol = useMemo(() => {
|
||||
return selectedMarket?.name.split('/')[0]
|
||||
}, [selectedMarket])
|
||||
|
||||
const coingeckoData = coingeckoPrices.find((asset) =>
|
||||
const coingeckoData = tokenPrices.find((asset) =>
|
||||
baseSymbol === 'soETH'
|
||||
? asset.symbol === 'ETH'
|
||||
: asset.symbol === baseSymbol
|
||||
|
|
|
@ -36,6 +36,7 @@ import { TRADE_FORM_UI_KEY } from 'utils/constants'
|
|||
import SpotButtonGroup from './SpotButtonGroup'
|
||||
import PerpButtonGroup from './PerpButtonGroup'
|
||||
import SolBalanceWarnings from '@components/shared/SolBalanceWarnings'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
|
||||
const TABS: [string, number][] = [
|
||||
['Limit', 0],
|
||||
|
@ -46,7 +47,7 @@ const AdvancedTradeForm = () => {
|
|||
const { t } = useTranslation(['common', 'trade'])
|
||||
const set = mangoStore.getState().set
|
||||
const tradeForm = mangoStore((s) => s.tradeForm)
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
const [useMargin, setUseMargin] = useState(true)
|
||||
const [placingOrder, setPlacingOrder] = useState(false)
|
||||
|
@ -57,13 +58,13 @@ const AdvancedTradeForm = () => {
|
|||
}, [selectedMarket])
|
||||
|
||||
const baseLogoURI = useMemo(() => {
|
||||
if (!baseSymbol || !jupiterTokens.length) return ''
|
||||
const token = jupiterTokens.find((t) => t.symbol === baseSymbol)
|
||||
if (!baseSymbol || !mangoTokens.length) return ''
|
||||
const token = mangoTokens.find((t) => t.symbol === baseSymbol)
|
||||
if (token) {
|
||||
return token.logoURI
|
||||
}
|
||||
return ''
|
||||
}, [baseSymbol, jupiterTokens])
|
||||
}, [baseSymbol, mangoTokens])
|
||||
|
||||
const quoteBank = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
|
@ -80,13 +81,13 @@ const AdvancedTradeForm = () => {
|
|||
}, [quoteBank])
|
||||
|
||||
const quoteLogoURI = useMemo(() => {
|
||||
if (!quoteSymbol || !jupiterTokens.length) return ''
|
||||
const token = jupiterTokens.find((t) => t.symbol === quoteSymbol)
|
||||
if (!quoteSymbol || !mangoTokens.length) return ''
|
||||
const token = mangoTokens.find((t) => t.symbol === quoteSymbol)
|
||||
if (token) {
|
||||
return token.logoURI
|
||||
}
|
||||
return ''
|
||||
}, [quoteSymbol, jupiterTokens])
|
||||
}, [quoteSymbol, mangoTokens])
|
||||
|
||||
const setTradeType = useCallback(
|
||||
(tradeType: 'Limit' | 'Market') => {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Serum3Market, PerpMarket } from '@blockworks-foundation/mango-v4'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import Image from 'next/legacy/image'
|
||||
|
@ -6,10 +7,10 @@ import { useMemo } from 'react'
|
|||
|
||||
const MarketLogos = ({ market }: { market: Serum3Market | PerpMarket }) => {
|
||||
const group = mangoStore((s) => s.group)
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
|
||||
const logos = useMemo(() => {
|
||||
if (!group || !jupiterTokens.length || !market)
|
||||
if (!group || !mangoTokens.length || !market)
|
||||
return { baseLogoURI: '', quoteLogoURI: '' }
|
||||
|
||||
let jupiterBaseToken, jupiterQuoteToken
|
||||
|
@ -17,14 +18,14 @@ const MarketLogos = ({ market }: { market: Serum3Market | PerpMarket }) => {
|
|||
const baseBank = group.getFirstBankByTokenIndex(market.baseTokenIndex)
|
||||
const quoteBank = group.getFirstBankByTokenIndex(market.quoteTokenIndex)
|
||||
|
||||
jupiterBaseToken = jupiterTokens.find(
|
||||
jupiterBaseToken = mangoTokens.find(
|
||||
(t) => t.address === baseBank.mint.toString()
|
||||
)
|
||||
jupiterQuoteToken = jupiterTokens.find(
|
||||
jupiterQuoteToken = mangoTokens.find(
|
||||
(t) => t.address === quoteBank.mint.toString()
|
||||
)
|
||||
} else {
|
||||
jupiterBaseToken = jupiterTokens.find(
|
||||
jupiterBaseToken = mangoTokens.find(
|
||||
(t) => t.symbol === market.name.split('-')[0]
|
||||
)
|
||||
}
|
||||
|
@ -34,7 +35,7 @@ const MarketLogos = ({ market }: { market: Serum3Market | PerpMarket }) => {
|
|||
baseLogoURI,
|
||||
quoteLogoURI,
|
||||
}
|
||||
}, [group, jupiterTokens, market])
|
||||
}, [group, mangoTokens, market])
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { PerpMarket, Serum3Market } from '@blockworks-foundation/mango-v4'
|
||||
import { PerpMarket } from '@blockworks-foundation/mango-v4'
|
||||
import LeverageSlider from '@components/swap/LeverageSlider'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import Decimal from 'decimal.js'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { notify } from 'utils/notifications'
|
||||
|
@ -75,6 +74,7 @@ const PerpSlider = () => {
|
|||
}
|
||||
leverageMax={leverageMax}
|
||||
onChange={handleSlide}
|
||||
step={0.01}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -74,6 +74,7 @@ const SpotSlider = () => {
|
|||
}
|
||||
leverageMax={leverageMax}
|
||||
onChange={handleSlide}
|
||||
step={0.01}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -20,7 +20,6 @@ const UnsettledTrades = ({
|
|||
const { t } = useTranslation(['common', 'trade'])
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const group = mangoStore((s) => s.group)
|
||||
// const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const [settleMktAddress, setSettleMktAddress] = useState<string>('')
|
||||
const { width } = useViewport()
|
||||
const showTableView = width ? width > breakpoints.md : false
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Token } from 'types/jupiter'
|
||||
import useJupiterMints from './useJupiterMints'
|
||||
|
||||
const fetchCoingecko = async (
|
||||
mangoTokens: Token[]
|
||||
): Promise<{ prices: any[]; symbol: string }[]> => {
|
||||
const coingeckoIds = mangoTokens.map((token) => ({
|
||||
id: token.extensions?.coingeckoId,
|
||||
symbol: token.symbol,
|
||||
}))
|
||||
const promises: any = []
|
||||
for (const token of coingeckoIds) {
|
||||
if (token.id) {
|
||||
promises.push(
|
||||
fetch(
|
||||
`https://api.coingecko.com/api/v3/coins/${token.id}/market_chart?vs_currency=usd&days=1`
|
||||
).then((res) => res.json())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const data = await Promise.all(promises)
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
data[i].symbol = coingeckoIds[i].symbol
|
||||
}
|
||||
|
||||
return data || []
|
||||
}
|
||||
|
||||
export const useCoingecko = () => {
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
|
||||
const res = useQuery<any[], Error>(
|
||||
['coingecko-tokens'],
|
||||
() => fetchCoingecko(mangoTokens!),
|
||||
{
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 2,
|
||||
retry: true,
|
||||
enabled: !!mangoTokens,
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
isLoading: res.isLoading,
|
||||
data: res.data || [],
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
import { Group } from '@blockworks-foundation/mango-v4'
|
||||
import { CLUSTER } from '@store/mangoStore'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import { Token } from 'types/jupiter'
|
||||
|
||||
const fetchJupiterTokens = async (group: Group) => {
|
||||
const url =
|
||||
CLUSTER === 'devnet'
|
||||
? 'https://api.jup.ag/api/tokens/devnet'
|
||||
: 'https://cache.jup.ag/tokens'
|
||||
const response = await fetch(url)
|
||||
const data = await response.json()
|
||||
|
||||
const bankMints = Array.from(group!.banksMapByName.values()).map((b) =>
|
||||
b[0].mint.toString()
|
||||
)
|
||||
const mangoTokens = data.filter((t: any) => bankMints.includes(t.address))
|
||||
|
||||
return {
|
||||
mangoTokens,
|
||||
jupiterTokens: data,
|
||||
}
|
||||
}
|
||||
|
||||
const useJupiterMints = (): {
|
||||
mangoTokens: Token[]
|
||||
jupiterTokens: Token[]
|
||||
isFetching: boolean
|
||||
} => {
|
||||
const { group } = useMangoGroup()
|
||||
|
||||
const res = useQuery<{ mangoTokens: Token[]; jupiterTokens: Token[] }, Error>(
|
||||
['jupiter-mango-tokens'],
|
||||
() => fetchJupiterTokens(group!),
|
||||
{
|
||||
cacheTime: 1000 * 60 * 10,
|
||||
staleTime: 1000 * 60 * 10,
|
||||
retry: true,
|
||||
enabled: !!group,
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
mangoTokens: res?.data?.mangoTokens || [],
|
||||
jupiterTokens: res?.data?.jupiterTokens || [],
|
||||
isFetching: res?.isFetching || false,
|
||||
}
|
||||
}
|
||||
|
||||
export default useJupiterMints
|
|
@ -0,0 +1,10 @@
|
|||
import { Group } from '@blockworks-foundation/mango-v4'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
|
||||
export default function useMangoGroup(): {
|
||||
group: Group | undefined
|
||||
} {
|
||||
const group = mangoStore((s) => s.group)
|
||||
|
||||
return { group }
|
||||
}
|
|
@ -15,7 +15,6 @@
|
|||
"@blockworks-foundation/mango-v4": "https://tylersssss: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@github.com/blockworks-foundation/mango-v4.git#main",
|
||||
"@headlessui/react": "^1.6.6",
|
||||
"@heroicons/react": "^2.0.10",
|
||||
"@jup-ag/core": "^2.0.0-beta.3",
|
||||
"@project-serum/anchor": "0.25.0",
|
||||
"@solana/wallet-adapter-base": "^0.9.18",
|
||||
"@solana/wallet-adapter-react": "^0.15.24",
|
||||
|
@ -31,7 +30,6 @@
|
|||
"decimal.js": "^10.4.0",
|
||||
"html-react-parser": "^3.0.4",
|
||||
"immer": "^9.0.12",
|
||||
"jsbi": "^4.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"next": "^13.0.0",
|
||||
"next-i18next": "^11.1.1",
|
||||
|
@ -55,6 +53,7 @@
|
|||
"@project-serum/serum": ">=0.13.62"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/big.js": "^6.1.6",
|
||||
"@types/node": "17.0.23",
|
||||
"@types/react": "18.0.3",
|
||||
"@types/react-dom": "18.0.0",
|
||||
|
|
|
@ -26,6 +26,9 @@ import ChartRangeButtons from '@components/shared/ChartRangeButtons'
|
|||
import dynamic from 'next/dynamic'
|
||||
import { LISTED_TOKENS } from 'utils/tokens'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
import { useCoingecko } from 'hooks/useCoingecko'
|
||||
const PriceChart = dynamic(() => import('@components/token/PriceChart'), {
|
||||
ssr: false,
|
||||
})
|
||||
|
@ -74,13 +77,12 @@ const Token: NextPage = () => {
|
|||
const [loading, setLoading] = useState(true)
|
||||
const router = useRouter()
|
||||
const { token } = router.query
|
||||
const group = mangoStore((s) => s.group)
|
||||
const { group } = useMangoGroup()
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data)
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const { isLoading: loadingPrices, data: coingeckoPrices } = useCoingecko()
|
||||
const [chartData, setChartData] = useState<{ prices: any[] } | null>(null)
|
||||
const [loadChartData, setLoadChartData] = useState(true)
|
||||
const loadingCoingeckoPrices = mangoStore((s) => s.coingeckoPrices.loading)
|
||||
const [daysToShow, setDaysToShow] = useState<number>(1)
|
||||
|
||||
const bank = useMemo(() => {
|
||||
|
@ -95,18 +97,18 @@ const Token: NextPage = () => {
|
|||
}, [group, token])
|
||||
|
||||
const logoURI = useMemo(() => {
|
||||
if (bank && jupiterTokens.length) {
|
||||
return jupiterTokens.find((t) => t.address === bank.mint.toString())
|
||||
if (bank && mangoTokens.length) {
|
||||
return mangoTokens.find((t) => t.address === bank.mint.toString())
|
||||
?.logoURI
|
||||
}
|
||||
}, [bank, jupiterTokens])
|
||||
}, [bank, mangoTokens])
|
||||
|
||||
const coingeckoId = useMemo(() => {
|
||||
if (bank && jupiterTokens.length) {
|
||||
return jupiterTokens.find((t) => t.address === bank.mint.toString())
|
||||
if (bank && mangoTokens.length) {
|
||||
return mangoTokens.find((t) => t.address === bank.mint.toString())
|
||||
?.extensions?.coingeckoId
|
||||
}
|
||||
}, [bank, jupiterTokens])
|
||||
}, [bank, mangoTokens])
|
||||
|
||||
const serumMarkets = useMemo(() => {
|
||||
if (group) {
|
||||
|
@ -137,13 +139,13 @@ const Token: NextPage = () => {
|
|||
return data
|
||||
}
|
||||
|
||||
const getCoingeckoData = async (id: string) => {
|
||||
const response = await fetchTokenInfo(id)
|
||||
setCoingeckoData(response)
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const getCoingeckoData = async (id: string) => {
|
||||
const response = await fetchTokenInfo(id)
|
||||
setCoingeckoData(response)
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
if (coingeckoId) {
|
||||
getCoingeckoData(coingeckoId)
|
||||
}
|
||||
|
@ -168,16 +170,15 @@ const Token: NextPage = () => {
|
|||
} = coingeckoData ? coingeckoData.market_data : DEFAULT_COINGECKO_VALUES
|
||||
|
||||
const loadingChart = useMemo(() => {
|
||||
return daysToShow == 1 ? loadingCoingeckoPrices : loadChartData
|
||||
}, [loadChartData, loadingCoingeckoPrices])
|
||||
return daysToShow == 1 ? loadingPrices : loadChartData
|
||||
}, [loadChartData, loadingPrices])
|
||||
|
||||
const coingeckoTokenPrices = useMemo(() => {
|
||||
if (daysToShow === 1 && coingeckoPrices.length && bank) {
|
||||
const tokenPriceData = coingeckoPrices.find((asset) =>
|
||||
bank?.name === 'soETH'
|
||||
? asset.symbol === 'ETH'
|
||||
: asset.symbol === bank.name
|
||||
const tokenPriceData = coingeckoPrices.find(
|
||||
(asset) => asset.symbol === bank.name
|
||||
)
|
||||
|
||||
if (tokenPriceData) {
|
||||
return tokenPriceData.prices
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import create from 'zustand'
|
|||
import { subscribeWithSelector } from 'zustand/middleware'
|
||||
import { AnchorProvider, Wallet, web3 } from '@project-serum/anchor'
|
||||
import { Connection, Keypair, PublicKey } from '@solana/web3.js'
|
||||
import { TOKEN_LIST_URL } from '@jup-ag/core'
|
||||
import { OpenOrders, Order } from '@project-serum/serum/lib/market'
|
||||
import { Wallet as WalletAdapter } from '@solana/wallet-adapter-react'
|
||||
import {
|
||||
|
@ -45,7 +44,7 @@ export const connection = new web3.Connection(
|
|||
'processed'
|
||||
)
|
||||
const options = AnchorProvider.defaultOptions()
|
||||
export const CLUSTER = 'mainnet-beta'
|
||||
export const CLUSTER: 'mainnet-beta' | 'devnet' = 'mainnet-beta'
|
||||
const wallet = new EmptyWallet(Keypair.generate())
|
||||
const DEFAULT_PROVIDER = new AnchorProvider(connection, wallet, options)
|
||||
DEFAULT_PROVIDER.opts.skipPreflight = true
|
||||
|
@ -164,16 +163,11 @@ export type MangoStore = {
|
|||
initialLoad: boolean
|
||||
loading: boolean
|
||||
}
|
||||
coingeckoPrices: {
|
||||
data: any[]
|
||||
loading: boolean
|
||||
}
|
||||
connected: boolean
|
||||
connection: Connection
|
||||
group: Group | undefined
|
||||
groupLoaded: boolean
|
||||
client: MangoClient
|
||||
jupiterTokens: Token[]
|
||||
mangoAccount: {
|
||||
current: MangoAccount | undefined
|
||||
initialLoad: boolean
|
||||
|
@ -246,9 +240,7 @@ export type MangoStore = {
|
|||
mangoAccountPk: string,
|
||||
range: number
|
||||
) => Promise<void>
|
||||
fetchCoingeckoPrices: () => Promise<void>
|
||||
fetchGroup: () => Promise<void>
|
||||
fetchJupiterTokens: () => Promise<void>
|
||||
reloadMangoAccount: () => Promise<void>
|
||||
fetchMangoAccounts: (wallet: Wallet) => Promise<void>
|
||||
fetchNfts: (connection: Connection, walletPk: PublicKey) => void
|
||||
|
@ -270,16 +262,11 @@ const mangoStore = create<MangoStore>()(
|
|||
initialLoad: false,
|
||||
loading: true,
|
||||
},
|
||||
coingeckoPrices: {
|
||||
data: [],
|
||||
loading: false,
|
||||
},
|
||||
connected: false,
|
||||
connection,
|
||||
group: undefined,
|
||||
groupLoaded: false,
|
||||
client: DEFAULT_CLIENT,
|
||||
jupiterTokens: [],
|
||||
mangoAccount: {
|
||||
current: undefined,
|
||||
initialLoad: true,
|
||||
|
@ -477,45 +464,6 @@ const mangoStore = create<MangoStore>()(
|
|||
})
|
||||
}
|
||||
},
|
||||
fetchCoingeckoPrices: async () => {
|
||||
const set = get().set
|
||||
set((state) => {
|
||||
state.coingeckoPrices.loading = true
|
||||
})
|
||||
try {
|
||||
const jupiterTokens = mangoStore.getState().jupiterTokens
|
||||
if (jupiterTokens.length) {
|
||||
const coingeckoIds = jupiterTokens.map((token) => ({
|
||||
id: token.extensions?.coingeckoId,
|
||||
symbol: token.symbol,
|
||||
}))
|
||||
const promises: any = []
|
||||
for (const token of coingeckoIds) {
|
||||
if (token.id) {
|
||||
promises.push(
|
||||
fetch(
|
||||
`https://api.coingecko.com/api/v3/coins/${token.id}/market_chart?vs_currency=usd&days=1`
|
||||
).then((res) => res.json())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const data = await Promise.all(promises)
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
data[i].symbol = coingeckoIds[i].symbol
|
||||
}
|
||||
set((state) => {
|
||||
state.coingeckoPrices.data = data
|
||||
state.coingeckoPrices.loading = false
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Unable to load Coingecko prices')
|
||||
set((state) => {
|
||||
state.coingeckoPrices.loading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
fetchGroup: async () => {
|
||||
try {
|
||||
const set = get().set
|
||||
|
@ -771,38 +719,6 @@ const mangoStore = create<MangoStore>()(
|
|||
})
|
||||
}
|
||||
},
|
||||
fetchJupiterTokens: async () => {
|
||||
const set = mangoStore.getState().set
|
||||
const group = mangoStore.getState().group
|
||||
if (!group) {
|
||||
console.error(
|
||||
'Mango group unavailable; Loading jupiter tokens failed'
|
||||
)
|
||||
return
|
||||
}
|
||||
const bankMints = Array.from(group.banksMapByName.values()).map((b) =>
|
||||
b[0].mint.toString()
|
||||
)
|
||||
|
||||
fetch(TOKEN_LIST_URL[CLUSTER])
|
||||
.then((response) => response.json())
|
||||
.then((result) => {
|
||||
const groupTokens = result.filter((t: any) =>
|
||||
bankMints.includes(t.address)
|
||||
)
|
||||
const inputTokenInfo = groupTokens.find(
|
||||
(t: any) => t.symbol === INPUT_TOKEN_DEFAULT
|
||||
)
|
||||
const outputTokenInfo = groupTokens.find(
|
||||
(t: any) => t.symbol === OUTPUT_TOKEN_DEFAULT
|
||||
)
|
||||
set((s) => {
|
||||
s.swap.inputTokenInfo = inputTokenInfo
|
||||
s.swap.outputTokenInfo = outputTokenInfo
|
||||
s.jupiterTokens = groupTokens
|
||||
})
|
||||
})
|
||||
},
|
||||
connectMangoClientWithWallet: async (wallet: WalletAdapter) => {
|
||||
const set = get().set
|
||||
try {
|
||||
|
|
130
types/jupiter.ts
130
types/jupiter.ts
|
@ -1,6 +1,134 @@
|
|||
import { RouteInfo } from '@jup-ag/core'
|
||||
import { AccountMeta } from '@solana/web3.js'
|
||||
import { AccountInfo } from '@solana/web3.js'
|
||||
import Decimal from 'decimal.js'
|
||||
|
||||
export declare type SideType = typeof Side.Ask | typeof Side.Bid
|
||||
export declare const Side: {
|
||||
Bid: {
|
||||
bid: {}
|
||||
}
|
||||
Ask: {
|
||||
ask: {}
|
||||
}
|
||||
}
|
||||
|
||||
export interface QuoteParams {
|
||||
sourceMint: string
|
||||
destinationMint: string
|
||||
amount: number
|
||||
swapMode: SwapMode
|
||||
}
|
||||
export declare type TokenMintAddress = string
|
||||
export interface Quote {
|
||||
notEnoughLiquidity: boolean
|
||||
minInAmount?: number
|
||||
minOutAmount?: number
|
||||
inAmount: number
|
||||
outAmount: number
|
||||
feeAmount: number
|
||||
feeMint: TokenMintAddress
|
||||
feePct: number
|
||||
priceImpactPct: number
|
||||
}
|
||||
export declare type QuoteMintToReferrer = Map<TokenMintAddress, string>
|
||||
export interface SwapParams {
|
||||
sourceMint: string
|
||||
destinationMint: string
|
||||
userSourceTokenAccount: string
|
||||
userDestinationTokenAccount: string
|
||||
userTransferAuthority: string
|
||||
/**
|
||||
* amount is used for instruction and can be null when it is an intermediate swap, only the first swap has an amount
|
||||
*/
|
||||
amount: number
|
||||
swapMode: SwapMode
|
||||
openOrdersAddress?: string
|
||||
quoteMintToReferrer?: QuoteMintToReferrer
|
||||
}
|
||||
export declare type PlatformFee = {
|
||||
feeBps: number
|
||||
feeAccount: string
|
||||
}
|
||||
export interface ExactOutSwapParams extends SwapParams {
|
||||
inAmount: number
|
||||
slippageBps: number
|
||||
platformFee?: PlatformFee
|
||||
overflowFeeAccount?: string
|
||||
}
|
||||
export declare type AccountInfoMap = Map<string, AccountInfo<Buffer> | null>
|
||||
|
||||
declare type AmmLabel =
|
||||
| 'Aldrin'
|
||||
| 'Crema'
|
||||
| 'Cropper'
|
||||
| 'Cykura'
|
||||
| 'DeltaFi'
|
||||
| 'GooseFX'
|
||||
| 'Invariant'
|
||||
| 'Lifinity'
|
||||
| 'Lifinity V2'
|
||||
| 'Marinade'
|
||||
| 'Mercurial'
|
||||
| 'Meteora'
|
||||
| 'Raydium'
|
||||
| 'Raydium CLMM'
|
||||
| 'Saber'
|
||||
| 'Serum'
|
||||
| 'Orca'
|
||||
| 'Step'
|
||||
| 'Penguin'
|
||||
| 'Saros'
|
||||
| 'Stepn'
|
||||
| 'Orca (Whirlpools)'
|
||||
| 'Sencha'
|
||||
| 'Saber (Decimals)'
|
||||
| 'Dradex'
|
||||
| 'Balansol'
|
||||
| 'Openbook'
|
||||
| 'Unknown'
|
||||
|
||||
export interface TransactionFeeInfo {
|
||||
signatureFee: number
|
||||
openOrdersDeposits: number[]
|
||||
ataDeposits: number[]
|
||||
totalFeeAndDeposits: number
|
||||
minimumSOLForTransaction: number
|
||||
}
|
||||
|
||||
export declare enum SwapMode {
|
||||
ExactIn = 'ExactIn',
|
||||
ExactOut = 'ExactOut',
|
||||
}
|
||||
|
||||
export interface Fee {
|
||||
amount: number
|
||||
mint: string
|
||||
pct: number
|
||||
}
|
||||
export interface MarketInfo {
|
||||
id: string
|
||||
inAmount: number
|
||||
inputMint: string
|
||||
label: string
|
||||
lpFee: Fee
|
||||
notEnoughLiquidity: boolean
|
||||
outAmount: number
|
||||
outputMint: string
|
||||
platformFee: Fee
|
||||
priceImpactPct: number
|
||||
}
|
||||
|
||||
export interface RouteInfo {
|
||||
amount: number
|
||||
inAmount: number
|
||||
marketInfos: MarketInfo[]
|
||||
otherAmountThreshold: number
|
||||
outAmount: number
|
||||
priceImpactPct: number
|
||||
slippageBps: number
|
||||
swapMode: SwapMode
|
||||
}
|
||||
|
||||
export type Routes = {
|
||||
routesInfos: RouteInfo[]
|
||||
cached: boolean
|
||||
|
|
|
@ -3,7 +3,8 @@ export const LAST_ACCOUNT_KEY = 'mangoAccount-0.1'
|
|||
export const CLIENT_TX_TIMEOUT = 90000
|
||||
|
||||
export const INPUT_TOKEN_DEFAULT = 'USDC'
|
||||
|
||||
export const MANGO_MINT = 'MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac'
|
||||
export const USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
|
||||
export const OUTPUT_TOKEN_DEFAULT = 'SOL'
|
||||
|
||||
export const IS_ONBOARDED_KEY = 'isOnboarded-0.1'
|
||||
|
|
Loading…
Reference in New Issue