2023-02-27 23:20:11 -08:00
|
|
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2023-01-12 13:22:46 -08:00
|
|
|
import { PublicKey } from '@solana/web3.js'
|
|
|
|
import { useQuery } from '@tanstack/react-query'
|
|
|
|
import Decimal from 'decimal.js'
|
|
|
|
import { RouteInfo } from 'types/jupiter'
|
|
|
|
import { MANGO_ROUTER_API_URL } from 'utils/constants'
|
|
|
|
import useJupiterSwapData from './useJupiterSwapData'
|
|
|
|
|
2023-06-28 10:19:02 -07:00
|
|
|
type SwapModes = 'ALL' | 'JUPITER' | 'MANGO'
|
|
|
|
|
2023-01-12 13:22:46 -08:00
|
|
|
type useQuoteRoutesPropTypes = {
|
|
|
|
inputMint: string
|
|
|
|
outputMint: string
|
|
|
|
amount: string
|
|
|
|
slippage: number
|
|
|
|
swapMode: string
|
|
|
|
wallet: string | undefined | null
|
2023-06-28 10:19:02 -07:00
|
|
|
mode?: SwapModes
|
2023-01-12 13:22:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
const fetchJupiterRoutes = async (
|
|
|
|
inputMint = 'So11111111111111111111111111111111111111112',
|
|
|
|
outputMint = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
|
|
amount = 0,
|
|
|
|
slippage = 50,
|
|
|
|
swapMode = 'ExactIn',
|
|
|
|
feeBps = 0
|
|
|
|
) => {
|
|
|
|
{
|
|
|
|
const paramsString = new URLSearchParams({
|
|
|
|
inputMint: inputMint.toString(),
|
|
|
|
outputMint: outputMint.toString(),
|
|
|
|
amount: amount.toString(),
|
|
|
|
slippageBps: Math.ceil(slippage * 100).toString(),
|
|
|
|
feeBps: feeBps.toString(),
|
|
|
|
swapMode,
|
|
|
|
}).toString()
|
|
|
|
|
|
|
|
const response = await fetch(
|
|
|
|
`https://quote-api.jup.ag/v4/quote?${paramsString}`
|
|
|
|
)
|
|
|
|
|
|
|
|
const res = await response.json()
|
|
|
|
const data = res.data
|
|
|
|
|
|
|
|
return {
|
|
|
|
routes: res.data as RouteInfo[],
|
|
|
|
bestRoute: (data.length ? data[0] : null) as RouteInfo | null,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const fetchMangoRoutes = async (
|
|
|
|
inputMint = 'So11111111111111111111111111111111111111112',
|
|
|
|
outputMint = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
|
|
amount = 0,
|
|
|
|
slippage = 50,
|
|
|
|
swapMode = 'ExactIn',
|
|
|
|
feeBps = 0,
|
|
|
|
wallet = PublicKey.default.toBase58()
|
|
|
|
) => {
|
|
|
|
{
|
|
|
|
const defaultOtherAmount =
|
|
|
|
swapMode === 'ExactIn' ? 0 : Number.MAX_SAFE_INTEGER
|
|
|
|
|
|
|
|
const paramsString = new URLSearchParams({
|
|
|
|
inputMint: inputMint.toString(),
|
|
|
|
outputMint: outputMint.toString(),
|
|
|
|
amount: amount.toString(),
|
|
|
|
slippage: ((slippage * 1) / 100).toString(),
|
|
|
|
feeBps: feeBps.toString(),
|
|
|
|
mode: swapMode,
|
|
|
|
wallet: wallet,
|
|
|
|
otherAmountThreshold: defaultOtherAmount.toString(),
|
|
|
|
}).toString()
|
|
|
|
|
|
|
|
const response = await fetch(`${MANGO_ROUTER_API_URL}/swap?${paramsString}`)
|
|
|
|
|
|
|
|
const res = await response.json()
|
|
|
|
const data: RouteInfo[] = res.map((route: any) => ({
|
|
|
|
...route,
|
|
|
|
priceImpactPct: route.priceImpact,
|
|
|
|
slippageBps: slippage,
|
|
|
|
marketInfos: route.marketInfos.map((mInfo: any) => ({
|
|
|
|
...mInfo,
|
|
|
|
lpFee: {
|
|
|
|
...mInfo.fee,
|
|
|
|
pct: mInfo.fee.rate,
|
|
|
|
},
|
|
|
|
})),
|
2023-01-15 05:15:35 -08:00
|
|
|
mints: route.mints.map((x: string) => new PublicKey(x)),
|
2023-01-14 17:05:45 -08:00
|
|
|
instructions: route.instructions.map((ix: any) => ({
|
|
|
|
...ix,
|
|
|
|
programId: new PublicKey(ix.programId),
|
|
|
|
data: Buffer.from(ix.data, 'base64'),
|
|
|
|
keys: ix.keys.map((key: any) => ({
|
|
|
|
...key,
|
|
|
|
pubkey: new PublicKey(key.pubkey),
|
|
|
|
})),
|
|
|
|
})),
|
2023-01-15 05:15:35 -08:00
|
|
|
routerName: 'Mango',
|
2023-01-12 13:22:46 -08:00
|
|
|
}))
|
|
|
|
return {
|
|
|
|
routes: data,
|
|
|
|
bestRoute: (data.length ? data[0] : null) as RouteInfo | null,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-05 14:59:30 -07:00
|
|
|
export const handleGetRoutes = async (
|
2023-01-12 13:22:46 -08:00
|
|
|
inputMint = 'So11111111111111111111111111111111111111112',
|
|
|
|
outputMint = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
|
|
amount = 0,
|
|
|
|
slippage = 50,
|
|
|
|
swapMode = 'ExactIn',
|
|
|
|
feeBps = 0,
|
2023-06-06 15:54:44 -07:00
|
|
|
wallet: string | undefined | null,
|
2023-06-28 10:19:02 -07:00
|
|
|
mode: SwapModes = 'ALL'
|
2023-01-12 13:22:46 -08:00
|
|
|
) => {
|
2023-02-04 13:55:42 -08:00
|
|
|
try {
|
|
|
|
wallet ||= PublicKey.default.toBase58()
|
2023-06-06 15:54:44 -07:00
|
|
|
const mangoRoute = fetchMangoRoutes(
|
|
|
|
inputMint,
|
|
|
|
outputMint,
|
|
|
|
amount,
|
|
|
|
slippage,
|
|
|
|
swapMode,
|
|
|
|
feeBps,
|
|
|
|
wallet
|
|
|
|
)
|
|
|
|
const jupiterRoute = fetchJupiterRoutes(
|
|
|
|
inputMint,
|
|
|
|
outputMint,
|
|
|
|
amount,
|
|
|
|
slippage,
|
|
|
|
swapMode,
|
|
|
|
feeBps
|
|
|
|
)
|
|
|
|
|
|
|
|
const routes = []
|
|
|
|
if (mode == 'ALL') {
|
|
|
|
routes.push(mangoRoute)
|
|
|
|
routes.push(jupiterRoute)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode === 'MANGO') {
|
|
|
|
routes.push(mangoRoute)
|
|
|
|
}
|
|
|
|
if (mode === 'JUPITER') {
|
|
|
|
routes.push(jupiterRoute)
|
|
|
|
}
|
2023-01-12 13:22:46 -08:00
|
|
|
|
2023-06-06 15:54:44 -07:00
|
|
|
const results = await Promise.allSettled(routes)
|
2023-02-04 13:55:42 -08:00
|
|
|
const responses = results
|
|
|
|
.filter((x) => x.status === 'fulfilled' && x.value.bestRoute !== null)
|
|
|
|
.map((x) => (x as any).value)
|
|
|
|
|
|
|
|
const sortedByBiggestOutAmount = (
|
|
|
|
responses as {
|
|
|
|
routes: RouteInfo[]
|
|
|
|
bestRoute: RouteInfo
|
|
|
|
}[]
|
|
|
|
).sort(
|
|
|
|
(a, b) => Number(b.bestRoute.outAmount) - Number(a.bestRoute.outAmount)
|
|
|
|
)
|
|
|
|
return {
|
|
|
|
routes: sortedByBiggestOutAmount[0].routes,
|
|
|
|
bestRoute: sortedByBiggestOutAmount[0].bestRoute,
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return {
|
|
|
|
routes: [],
|
|
|
|
bestRoute: null,
|
|
|
|
}
|
2023-01-12 13:22:46 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const useQuoteRoutes = ({
|
|
|
|
inputMint,
|
|
|
|
outputMint,
|
|
|
|
amount,
|
|
|
|
slippage,
|
|
|
|
swapMode,
|
|
|
|
wallet,
|
2023-06-28 10:19:02 -07:00
|
|
|
mode = 'ALL',
|
2023-01-12 13:22:46 -08:00
|
|
|
}: useQuoteRoutesPropTypes) => {
|
|
|
|
const { inputTokenInfo, outputTokenInfo } = useJupiterSwapData()
|
|
|
|
|
|
|
|
const decimals =
|
|
|
|
swapMode === 'ExactIn'
|
|
|
|
? inputTokenInfo?.decimals || 6
|
|
|
|
: outputTokenInfo?.decimals || 6
|
|
|
|
|
|
|
|
const nativeAmount =
|
|
|
|
amount && !Number.isNaN(+amount)
|
|
|
|
? new Decimal(amount).mul(10 ** decimals)
|
|
|
|
: new Decimal(0)
|
|
|
|
|
2023-02-04 13:55:42 -08:00
|
|
|
const res = useQuery<
|
|
|
|
{ routes: RouteInfo[]; bestRoute: RouteInfo | null },
|
|
|
|
Error
|
|
|
|
>(
|
2023-01-12 13:22:46 -08:00
|
|
|
['swap-routes', inputMint, outputMint, amount, slippage, swapMode, wallet],
|
|
|
|
async () =>
|
|
|
|
handleGetRoutes(
|
|
|
|
inputMint,
|
|
|
|
outputMint,
|
|
|
|
nativeAmount.toNumber(),
|
|
|
|
slippage,
|
|
|
|
swapMode,
|
|
|
|
0,
|
2023-06-28 10:19:02 -07:00
|
|
|
wallet,
|
|
|
|
mode
|
2023-01-12 13:22:46 -08:00
|
|
|
),
|
|
|
|
{
|
2023-01-20 08:13:03 -08:00
|
|
|
cacheTime: 1000 * 60,
|
|
|
|
staleTime: 1000 * 30,
|
2023-01-12 13:22:46 -08:00
|
|
|
enabled: amount ? true : false,
|
2023-01-20 08:13:03 -08:00
|
|
|
retry: 3,
|
2023-01-12 13:22:46 -08:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
return amount
|
|
|
|
? {
|
|
|
|
...(res.data ?? {
|
|
|
|
routes: [],
|
|
|
|
bestRoute: undefined,
|
|
|
|
}),
|
|
|
|
isLoading: res.isLoading,
|
|
|
|
}
|
|
|
|
: {
|
|
|
|
routes: [],
|
|
|
|
bestRoute: undefined,
|
|
|
|
isLoading: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default useQuoteRoutes
|