delegate-framework
Version:
A TypeScript framework for building robust, production-ready blockchain workflows with comprehensive error handling, logging, and testing. Maintained by delegate.fun
144 lines • 6.42 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JupiterSwap = void 0;
const web3_js_1 = require("@solana/web3.js");
const base_protocol_1 = require("./base-protocol");
class JupiterSwap extends base_protocol_1.BaseSwapProtocol {
constructor(keypair, connection, config = {}) {
super(keypair, connection);
this.connection = connection;
this.config = {
tokenListUrl: 'https://token.jup.ag/all', // Jupiter's public token list
fallbackDecimals: 6,
...config
};
this.heliusClient = config.heliusClient;
}
async getQuote(inputMint, outputMint, amount, slippage = 0.2) {
return this.handleError(async () => {
this.validateSwapParams(inputMint, outputMint, amount);
// Convert to Asset format for Jupiter
const fromAsset = { contractAddress: inputMint, decimals: 0 }; // We'll get decimals later
const toAsset = { contractAddress: outputMint, decimals: 0 };
// Get token info to get decimals
const fromToken = await this.getTokenInfo(inputMint);
const toToken = await this.getTokenInfo(outputMint);
fromAsset.decimals = fromToken.decimals;
toAsset.decimals = toToken.decimals;
const quote = await this.retryOperation(async () => {
const response = await fetch(`https://quote-api.jup.ag/v6/quote?inputMint=${inputMint}&outputMint=${outputMint}&amount=${amount * Math.pow(10, fromAsset.decimals)}&slippage=${slippage}`);
if (!response.ok) {
throw new Error(`Jupiter API error: ${response.statusText}`);
}
return response.json();
}, 3);
if (quote && quote.outAmount) {
return {
inputMint,
outputMint,
inputAmount: amount.toString(),
outputAmount: (parseInt(quote.outAmount) / Math.pow(10, toAsset.decimals)).toString(),
priceImpact: quote.priceImpactPct,
swapUsdValue: quote.swapUsdValue,
jupiterQuote: quote // Store original Jupiter quote
};
}
return null;
}, 'jupiter_get_quote');
}
async createSwapTransaction(quote) {
return this.handleError(async () => {
if (!quote['jupiterQuote']) {
throw new Error('Invalid quote: missing Jupiter quote data');
}
const { swapTransaction } = await this.retryOperation(async () => {
const response = await fetch('https://quote-api.jup.ag/v6/swap', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
quoteResponse: quote['jupiterQuote'],
userPublicKey: this.keypair.publicKey.toBase58(),
wrapAndUnwrapSol: true,
}),
});
if (!response.ok) {
throw new Error(`Jupiter API error: ${response.statusText}`);
}
return response.json();
}, 3);
const swapTransactionBuf = Buffer.from(swapTransaction, 'base64');
const transaction = web3_js_1.VersionedTransaction.deserialize(swapTransactionBuf);
return {
serialize: () => Buffer.from(transaction.serialize()),
sign: (signers) => transaction.sign(signers)
};
}, 'jupiter_create_transaction');
}
async executeSwap(transaction) {
return this.handleError(async () => {
transaction.sign([this.keypair]);
const signature = await this.retryOperation(async () => {
return await this.connection.sendTransaction(transaction, // Type assertion needed due to interface
{ skipPreflight: true, maxRetries: 2 });
}, 3);
const latestBlockhash = await this.retryOperation(async () => {
return await this.connection.getLatestBlockhash();
}, 3);
await this.retryOperation(async () => {
return await this.connection.confirmTransaction({
blockhash: latestBlockhash.blockhash,
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
signature
});
}, 3);
return {
success: true,
signature
};
}, 'jupiter_execute_swap');
}
async getTokenInfo(tokenAddress) {
try {
// Try Jupiter's public token list first
const response = await fetch(this.config.tokenListUrl);
if (!response.ok) {
throw new Error(`Failed to fetch token list: ${response.statusText}`);
}
const tokens = await response.json();
const token = tokens.find((t) => t.address === tokenAddress);
if (token && typeof token.decimals === 'number') {
return { decimals: token.decimals };
}
// Fallback: Try to get token info from HeliusClient if available
if (this.heliusClient) {
const tokenInfo = await this.heliusClient.getTokenInfo(tokenAddress);
if (tokenInfo) {
return tokenInfo;
}
}
// Final fallback: use configured default
console.warn(`Token ${tokenAddress} not found in token list, using default decimals: ${this.config.fallbackDecimals}`);
return { decimals: this.config.fallbackDecimals };
}
catch (error) {
console.warn(`Failed to get token info for ${tokenAddress}, using default decimals: ${this.config.fallbackDecimals}`, error);
return { decimals: this.config.fallbackDecimals };
}
}
/**
* Update configuration
*/
updateConfig(config) {
this.config = { ...this.config, ...config };
}
/**
* Get current configuration
*/
getConfig() {
return { ...this.config };
}
}
exports.JupiterSwap = JupiterSwap;
//# sourceMappingURL=jupiter.js.map