From 4d47dc32ce7bdeb0bed106d4ad3c31a7e0700669 Mon Sep 17 00:00:00 2001 From: Rudy Date: Sat, 8 Feb 2025 18:07:39 +0800 Subject: [PATCH] add swap func --- package.json | 2 +- src/api/swapAndReferrer.ts | 134 +++++++++++++++++++++++++++++++++++++ yarn.lock | 8 +-- 3 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 src/api/swapAndReferrer.ts diff --git a/package.json b/package.json index 9f3070a..11b1fba 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Raydium SDK V2 demo.", "license": "GPL-3.0", "dependencies": { - "@raydium-io/raydium-sdk-v2": "0.1.108-alpha", + "@raydium-io/raydium-sdk-v2": "0.1.111-alpha", "@solana/spl-token": "^0.4.6", "@solana/web3.js": "^1.95.3", "@triton-one/yellowstone-grpc": "^1.2.0", diff --git a/src/api/swapAndReferrer.ts b/src/api/swapAndReferrer.ts new file mode 100644 index 0000000..b9fabea --- /dev/null +++ b/src/api/swapAndReferrer.ts @@ -0,0 +1,134 @@ +import { Transaction, VersionedTransaction, sendAndConfirmTransaction } from '@solana/web3.js' +import { NATIVE_MINT } from '@solana/spl-token' +import axios from 'axios' +import { connection, owner, fetchTokenAccountData } from '../config' +import { API_URLS } from '@raydium-io/raydium-sdk-v2' + +interface SwapCompute { + id: string + success: true + version: 'V0' | 'V1' + openTime?: undefined + msg: undefined + data: { + swapType: 'BaseIn' | 'BaseOut' + inputMint: string + inputAmount: string + outputMint: string + outputAmount: string + otherAmountThreshold: string + slippageBps: number + priceImpactPct: number + routePlan: { + poolId: string + inputMint: string + outputMint: string + feeMint: string + feeRate: number + feeAmount: string + }[] + } +} + +export const apiSwap = async () => { + /** + * + * Please note that the refer function is currently only available for input mints of SOL, WSOL, USDC, and USDT. Other parameters will be ignored by default without triggering an error. + * + */ + + const inputMint = NATIVE_MINT.toBase58() + const outputMint = '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R' // RAY + const amount = 10000 + const slippage = 0.5 // in percent, for this example, 0.5 means 0.5% + const txVersion: string = 'V0' // or LEGACY + const isV0Tx = txVersion === 'V0' + const referrerBps = 100 + const referrerWallet = '' + + const [isInputSol, isOutputSol] = [inputMint === NATIVE_MINT.toBase58(), outputMint === NATIVE_MINT.toBase58()] + + const { tokenAccounts } = await fetchTokenAccountData() + const inputTokenAcc = tokenAccounts.find((a) => a.mint.toBase58() === inputMint)?.publicKey + const outputTokenAcc = tokenAccounts.find((a) => a.mint.toBase58() === outputMint)?.publicKey + + if (!inputTokenAcc && !isInputSol) { + console.error('do not have input token account') + return + } + + // get statistical transaction fee from api + /** + * vh: very high + * h: high + * m: medium + */ + const { data } = await axios.get<{ + id: string + success: boolean + data: { default: { vh: number; h: number; m: number } } + }>(`${API_URLS.BASE_HOST}${API_URLS.PRIORITY_FEE}`) + + console.log('inputMint', inputMint) + const { data: swapResponse } = await axios.get( + `${API_URLS.SWAP_HOST + }/compute/swap-base-in?inputMint=${inputMint}&outputMint=${outputMint}&amount=${amount}&slippageBps=${slippage * 100 + }&txVersion=${txVersion}&referrerBps=${referrerBps}` + ) + + const { data: swapTransactions } = await axios.post<{ + id: string + version: string + success: boolean + data: { transaction: string }[] + }>(`${API_URLS.SWAP_HOST}/transaction/swap-base-in`, { + computeUnitPriceMicroLamports: String(data.data.default.h), + swapResponse, + txVersion, + wallet: owner.publicKey.toBase58(), + wrapSol: isInputSol, + unwrapSol: isOutputSol, // true means output mint receive sol, false means output mint received wsol + inputAccount: isInputSol ? undefined : inputTokenAcc?.toBase58(), + outputAccount: isOutputSol ? undefined : outputTokenAcc?.toBase58(), + referrerWallet, + }) + + const allTxBuf = swapTransactions.data.map((tx) => Buffer.from(tx.transaction, 'base64')) + const allTransactions = allTxBuf.map((txBuf) => + isV0Tx ? VersionedTransaction.deserialize(txBuf) : Transaction.from(txBuf) + ) + + console.log(`total ${allTransactions.length} transactions`, swapTransactions) + + let idx = 0 + if (!isV0Tx) { + for (const tx of allTransactions) { + console.log(`${++idx} transaction sending...`) + const transaction = tx as Transaction + transaction.sign(owner) + const txId = await sendAndConfirmTransaction(connection, transaction, [owner], { skipPreflight: true }) + console.log(`${++idx} transaction confirmed, txId: ${txId}`) + } + } else { + for (const tx of allTransactions) { + idx++ + const transaction = tx as VersionedTransaction + transaction.sign([owner]) + const txId = await connection.sendTransaction(tx as VersionedTransaction, { skipPreflight: true }) + const { lastValidBlockHeight, blockhash } = await connection.getLatestBlockhash({ + commitment: 'finalized', + }) + console.log(`${idx} transaction sending..., txId: ${txId}`) + await connection.confirmTransaction( + { + blockhash, + lastValidBlockHeight, + signature: txId, + }, + 'confirmed' + ) + console.log(`${idx} transaction confirmed`) + } + } +} +apiSwap() diff --git a/yarn.lock b/yarn.lock index da4cd9f..e1f559b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -278,10 +278,10 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== -"@raydium-io/raydium-sdk-v2@0.1.108-alpha": - version "0.1.108-alpha" - resolved "https://registry.yarnpkg.com/@raydium-io/raydium-sdk-v2/-/raydium-sdk-v2-0.1.108-alpha.tgz#5f0b3ff3689c9e1ee1effebc0c8ba47873d84726" - integrity sha512-g2Z2ejVhwL1ZRpVA3bpwtYEOf4FnwpgTDzkhEJRo+xURP17QZ0xRUQ/rn7jOYmBI2qgA6iyykrfrCiamCRAeww== +"@raydium-io/raydium-sdk-v2@0.1.111-alpha": + version "0.1.111-alpha" + resolved "https://registry.yarnpkg.com/@raydium-io/raydium-sdk-v2/-/raydium-sdk-v2-0.1.111-alpha.tgz#622fd832ffacdc0dc9b6c4b9f70b7412ca986753" + integrity sha512-mIvwClYgiBgKsYWgM6sFWXpwxYeWhXvZpSOPA6+o0xuRSEBo2hmpuy98DdWOkSZwoUUg1oTKSdRGepBwtpZqQw== dependencies: "@solana/buffer-layout" "^4.0.1" "@solana/spl-token" "^0.4.8"