-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 95745e2
Showing
10 changed files
with
6,187 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import { | ||
createJupiterApiClient, | ||
QuoteGetRequest, | ||
SwapPostRequest, | ||
} from '@jup-ag/api'; | ||
|
||
export interface JupiterTokenPriceData { | ||
id: string; | ||
mintSymbol: string; | ||
vsToken: string; | ||
vsTokenSymbol: string; | ||
price: number; | ||
} | ||
|
||
interface JupiterPriceApiResponse { | ||
data: Record<string, JupiterTokenPriceData>; | ||
timeTaken: number; | ||
} | ||
|
||
export interface JupiterTokenMetadata { | ||
address: string; | ||
chainId: number; | ||
decimals: number; | ||
name?: string; | ||
symbol?: string; | ||
logoURI: string; | ||
tags: string[]; | ||
} | ||
|
||
export const createJupiterApi = () => { | ||
const jupiterApi = createJupiterApiClient(); | ||
|
||
const getTokenPricesInUsdc = async (tokenIds: string[]) => { | ||
if (tokenIds.length === 0) { | ||
return {}; | ||
} | ||
const url = `https://price.jup.ag/v4/price?ids=${tokenIds.join( | ||
',', | ||
)}&vsToken=USDC`; | ||
const response = await fetch(url); | ||
const parsedResponse = (await response.json()) as JupiterPriceApiResponse; | ||
return parsedResponse.data; | ||
}; | ||
|
||
const getTokenPriceInSol = async (tokenIds: string[]) => { | ||
if (tokenIds.length === 0) { | ||
return {}; | ||
} | ||
const url = `https://price.jup.ag/v4/price?ids=${tokenIds.join( | ||
',', | ||
)}&vsToken=SOL`; | ||
const response = await fetch(url); | ||
const parsedResponse = (await response.json()) as JupiterPriceApiResponse; | ||
return parsedResponse.data; | ||
}; | ||
|
||
const quoteGet = async (request: QuoteGetRequest) => { | ||
return await jupiterApi.quoteGet(request); | ||
}; | ||
|
||
const swapPost = async (request: SwapPostRequest) => { | ||
return await jupiterApi.swapPost(request); | ||
}; | ||
|
||
const getTokenList = async (): Promise<JupiterTokenMetadata[]> => { | ||
try { | ||
const response = await fetch('https://token.jup.ag/all'); | ||
|
||
if (!response.ok) { | ||
return []; | ||
} | ||
|
||
return await response.json(); | ||
} catch (e) { | ||
console.error(e); | ||
return []; | ||
} | ||
}; | ||
|
||
const getStrictList = async (): Promise<JupiterTokenMetadata[]> => { | ||
try { | ||
const response = await fetch('https://token.jup.ag/strict'); | ||
|
||
if (!response.ok) { | ||
return []; | ||
} | ||
|
||
return await response.json(); | ||
} catch (e) { | ||
console.error(e); | ||
return []; | ||
} | ||
}; | ||
|
||
const lookupToken = async ( | ||
token: string | null, | ||
): Promise<JupiterTokenMetadata | null> => { | ||
if (!token) { | ||
return null; | ||
} | ||
const tokenLowercase = token.toLowerCase().trim(); | ||
const jupiterTokenMetadata = await getStrictList(); | ||
|
||
const jupTokenMetaDatum = jupiterTokenMetadata.find( | ||
(token) => | ||
token.symbol?.toLowerCase() === tokenLowercase || | ||
token.address?.toLowerCase() === tokenLowercase, | ||
); | ||
|
||
return jupTokenMetaDatum ?? null; | ||
}; | ||
|
||
return { | ||
getTokenPricesInUsdc, | ||
getTokenPriceInSol, | ||
quoteGet, | ||
swapPost, | ||
lookupToken, | ||
}; | ||
}; | ||
|
||
const jupiterApi = createJupiterApi(); | ||
|
||
export default jupiterApi; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { PublicKey, Transaction } from '@solana/web3.js'; | ||
import { BN } from 'bn.js'; | ||
import { TokenInfo } from '@solana/spl-token-registry'; | ||
import AmmImpl from '@mercurial-finance/dynamic-amm-sdk'; | ||
import * as math from 'mathjs'; | ||
import { connection } from '../shared/connection'; | ||
import { createJupiterApi } from './jupiter-api'; | ||
|
||
export const createSwapTx = async ( | ||
userPublicKey: PublicKey, | ||
poolAddress: string, | ||
usdcAmount: string, | ||
token: string, | ||
referrer: string | null, | ||
): Promise<Transaction> => { | ||
const poolData = await fetch( | ||
`https://amm.meteora.ag/pools?address=${poolAddress}`, | ||
).then((res) => res.json()); | ||
const poolDetails = poolData[0]; | ||
|
||
const tokenList: TokenInfo[] = await fetch('https://token.jup.ag/all').then( | ||
(res) => res.json(), | ||
); | ||
const tokenADetails = tokenList.find( | ||
(item) => item && item.address === poolDetails.pool_token_mints[0], | ||
)!; | ||
const tokenBDetails = tokenList.find( | ||
(item) => item && item.address === poolDetails.pool_token_mints[1], | ||
)!; | ||
|
||
const ammPool = await AmmImpl.create( | ||
connection, | ||
new PublicKey(poolAddress), | ||
tokenADetails, | ||
tokenBDetails, | ||
); | ||
|
||
const inTokenDetails = | ||
tokenADetails.address === token ? tokenBDetails : tokenADetails; | ||
|
||
const { getTokenPricesInUsdc } = createJupiterApi(); | ||
const inToken = new PublicKey(inTokenDetails.address); | ||
const prices = await getTokenPricesInUsdc([inToken.toString()]); | ||
const tokenPriceUsd = prices[inToken.toString()]; | ||
|
||
const amount = parseFloat(usdcAmount) / tokenPriceUsd.price; | ||
|
||
const swapAmount = new BN( | ||
math | ||
.bignumber(amount) | ||
.mul(10 ** inTokenDetails.decimals) | ||
.floor() | ||
.toString(), | ||
); | ||
|
||
// Swap quote | ||
const swapQuote = ammPool.getSwapQuote(inToken, swapAmount, 10); | ||
|
||
// Swap | ||
const referrerKey = !referrer === false ? new PublicKey(referrer) : undefined; | ||
const swapTx = await ammPool.swap( | ||
userPublicKey, | ||
inToken, | ||
swapAmount, | ||
swapQuote.minSwapOutAmount, | ||
referrerKey, | ||
); | ||
return swapTx; | ||
}; | ||
|
||
export const getTokenPair = async ( | ||
poolAddress: string, | ||
token: string, | ||
): Promise<[PublicKey, PublicKey]> => { | ||
const poolData = await fetch( | ||
`https://amm.meteora.ag/pools?address=${poolAddress}`, | ||
).then((res) => res.json()); | ||
const poolDetails = poolData[0]; | ||
const tokenList: TokenInfo[] = await fetch('https://token.jup.ag/all').then( | ||
(res) => res.json(), | ||
); | ||
|
||
const tokenA = tokenList.find( | ||
(token) => token && token.address === poolDetails.pool_token_mints[0], | ||
); | ||
const tokenB = tokenList.find( | ||
(token) => token && token.address === poolDetails.pool_token_mints[1], | ||
); | ||
|
||
const inToken = tokenA!.address === token ? tokenB : tokenA; | ||
const outToken = tokenA!.address === token ? tokenA : tokenB; | ||
return [new PublicKey(inToken!.address), new PublicKey(outToken!.address)]; | ||
}; |
Oops, something went wrong.