Skip to content

Commit

Permalink
Use basic blinks actions on solana
Browse files Browse the repository at this point in the history
  • Loading branch information
kayx86 committed Jul 1, 2024
0 parents commit 95745e2
Show file tree
Hide file tree
Showing 10 changed files with 6,187 additions and 0 deletions.
124 changes: 124 additions & 0 deletions api/jupiter-api.ts
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;
93 changes: 93 additions & 0 deletions api/meteora-api.ts
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)];
};
Loading

0 comments on commit 95745e2

Please sign in to comment.