delegate-framework
Version:
A TypeScript framework for building robust, production-ready blockchain workflows with comprehensive error handling, logging, and testing. Maintained by delegate.fun
183 lines • 8.84 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RaydiumSwap = void 0;
const web3_js_1 = require("@solana/web3.js");
const spl_token_1 = require("@solana/spl-token");
const base_protocol_1 = require("./base-protocol");
const raydium_sdk_v2_1 = require("@raydium-io/raydium-sdk-v2");
class RaydiumSwap extends base_protocol_1.BaseSwapProtocol {
constructor(keypair, config = {}) {
super(keypair);
this.heliusClient = config.heliusClient;
}
async getQuote(inputMint, outputMint, amount, slippage = 0.5) {
return this.handleError(async () => {
this.validateSwapParams(inputMint, outputMint, amount);
const txVersion = 'V0';
const slippageBps = slippage * 100;
const swapComputeResponse = await this.retryOperation(async () => {
const response = await fetch(`${raydium_sdk_v2_1.API_URLS.SWAP_HOST}/compute/swap-base-in?inputMint=${inputMint}&outputMint=${outputMint}&amount=${amount}&slippageBps=${slippageBps}&txVersion=${txVersion}`);
if (!response.ok) {
throw new Error(`Raydium API error: ${response.statusText}`);
}
return response.json();
}, 3);
if (swapComputeResponse.success && swapComputeResponse.data) {
return {
inputMint,
outputMint,
inputAmount: amount.toString(),
outputAmount: swapComputeResponse.data.outputAmount,
priceImpact: swapComputeResponse.data.priceImpactPct,
raydiumQuote: swapComputeResponse // Store original Raydium quote
};
}
return null;
}, 'raydium_get_quote');
}
async createSwapTransaction(quote) {
return this.handleError(async () => {
if (!quote['raydiumQuote']) {
throw new Error('Invalid quote: missing Raydium quote data');
}
const txVersion = 'V0';
const isV0Tx = txVersion === 'V0';
// Get token accounts
const { tokenAccounts } = await this.fetchTokenAccountData();
const inputTokenAcc = tokenAccounts.find((a) => a.mint.toBase58() === quote.inputMint)?.publicKey;
const outputTokenAcc = tokenAccounts.find((a) => a.mint.toBase58() === quote.outputMint)?.publicKey;
const [isInputSol, isOutputSol] = [
quote.inputMint === spl_token_1.NATIVE_MINT.toBase58(),
quote.outputMint === spl_token_1.NATIVE_MINT.toBase58()
];
// Get priority fee
const feeResponse = await this.retryOperation(async () => {
const response = await fetch(`${raydium_sdk_v2_1.API_URLS.BASE_HOST}${raydium_sdk_v2_1.API_URLS.PRIORITY_FEE}`);
if (!response.ok) {
throw new Error(`Raydium API error: ${response.statusText}`);
}
return response.json();
}, 3);
// Create swap transaction
const swapTransactionsResponse = await this.retryOperation(async () => {
const response = await fetch(`${raydium_sdk_v2_1.API_URLS.SWAP_HOST}/transaction/swap-base-in`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
computeUnitPriceMicroLamports: String(feeResponse.data.default.h),
swapResponse: quote['raydiumQuote'],
txVersion,
wallet: this.keypair.publicKey.toBase58(),
wrapSol: isInputSol,
unwrapSol: isOutputSol,
inputAccount: isInputSol ? undefined : inputTokenAcc?.toBase58(),
outputAccount: isOutputSol ? undefined : outputTokenAcc?.toBase58(),
}),
});
if (!response.ok) {
throw new Error(`Raydium API error: ${response.statusText}`);
}
return response.json();
}, 3);
// Create transaction objects
const allTxBuf = swapTransactionsResponse.data.map((tx) => Buffer.from(tx.transaction, 'base64'));
const allTransactions = allTxBuf.map((txBuf) => isV0Tx ? web3_js_1.VersionedTransaction.deserialize(txBuf) : web3_js_1.Transaction.from(txBuf));
// Return the first transaction (Raydium usually returns single transaction)
const transaction = allTransactions[0];
return {
serialize: () => Buffer.from(transaction.serialize()),
sign: (signers) => {
if (isV0Tx) {
transaction.sign(signers);
}
else {
transaction.sign(...signers);
}
},
// Store additional data for execution
raydiumData: {
transaction,
isV0Tx,
allTransactions
}
};
}, 'raydium_create_transaction');
}
async executeSwap(transaction) {
return this.handleError(async () => {
const raydiumData = transaction.raydiumData;
if (!raydiumData) {
throw new Error('Invalid transaction: missing Raydium data');
}
const { transaction: tx, isV0Tx } = raydiumData;
if (isV0Tx) {
// Handle versioned transaction
const vtx = tx;
vtx.sign([this.keypair]);
const txId = await this.retryOperation(async () => {
return await this.connection.sendTransaction(vtx, { skipPreflight: true });
}, 3);
const { lastValidBlockHeight, blockhash } = await this.retryOperation(async () => {
return await this.connection.getLatestBlockhash({
commitment: 'finalized',
});
}, 3);
await this.retryOperation(async () => {
return await this.connection.confirmTransaction({
blockhash,
lastValidBlockHeight,
signature: txId,
}, 'confirmed');
}, 3);
return {
success: true,
signature: txId
};
}
else {
// Handle legacy transaction
const legacyTx = tx;
legacyTx.sign(this.keypair);
const txId = await this.retryOperation(async () => {
return await (0, web3_js_1.sendAndConfirmTransaction)(this.connection, legacyTx, [this.keypair], { skipPreflight: true });
}, 3);
return {
success: true,
signature: txId
};
}
}, 'raydium_execute_swap');
}
async fetchTokenAccountData() {
if (this.heliusClient) {
// Use HeliusClient if available
const walletData = await this.heliusClient.getWalletTokenData(this.keypair.publicKey.toBase58());
// Parse the data using Raydium's parser
const tokenAccountData = (0, raydium_sdk_v2_1.parseTokenAccountResp)({
owner: this.keypair.publicKey,
solAccountResp: walletData.solAccountInfo,
tokenAccountResp: walletData.tokenAccounts,
});
return tokenAccountData;
}
else {
// Fallback to direct RPC calls if no HeliusClient provided
const solAccountResp = await this.connection.getAccountInfo(this.keypair.publicKey);
const tokenAccountResp = await this.connection.getTokenAccountsByOwner(this.keypair.publicKey, { programId: spl_token_1.TOKEN_PROGRAM_ID });
const token2022Req = await this.connection.getTokenAccountsByOwner(this.keypair.publicKey, { programId: spl_token_1.TOKEN_2022_PROGRAM_ID });
const tokenAccountData = (0, raydium_sdk_v2_1.parseTokenAccountResp)({
owner: this.keypair.publicKey,
solAccountResp,
tokenAccountResp: {
context: tokenAccountResp.context,
value: [...tokenAccountResp.value, ...token2022Req.value],
},
});
return tokenAccountData;
}
}
}
exports.RaydiumSwap = RaydiumSwap;
//# sourceMappingURL=raydium.js.map